题解:burnside引理
DP出不动点的数目,用burnside引理算等价类
问题:不明白burnside引理的原理
#include<iostream> #include<cstdio> #include<cstring> using namespace std; int n,m,mm; int Sr,Sb,Sg; int tot; int a[100]; int vis[100]; int b[100],nn; int f[30][30][30]; void Calc(){ nn=0; memset(vis,0,sizeof(vis)); memset(f,0,sizeof(f)); memset(b,0,sizeof(b)); for(int i=1;i<=n;++i){ if(vis[i])continue; ++nn; int x=i; while(!vis[x]){ vis[x]=1;b[nn]++;x=a[x]; } } // for(int i=1;i<=nn;++i)cout<<b[i]<<‘ ‘; // cout<<endl; f[0][0][0]=1; for(int i=1;i<=nn;++i){ for(int x=Sr;x>=0;--x){ for(int y=Sb;y>=0;--y){ for(int z=Sg;z>=0;--z){ int t=b[i]; if(x>=t)f[x][y][z]+=f[x-t][y][z]; if(y>=t)f[x][y][z]+=f[x][y-t][z]; if(z>=t)f[x][y][z]+=f[x][y][z-t]; f[x][y][z]%=mm; } } } } tot=(tot+f[Sr][Sb][Sg])%mm; } int Ksm(int a,int p){ int ret=1; for(;p;p>>=1,a=a*a%mm){ if(p&1)ret=ret*a%mm; } return ret; } int main(){ scanf("%d%d%d%d%d",&Sr,&Sb,&Sg,&m,&mm); n=Sr+Sb+Sg; for(int k=1;k<=m;++k){ for(int i=1;i<=n;++i)scanf("%d",&a[i]); Calc(); } m++; for(int i=1;i<=n;++i)a[i]=i; Calc(); cout<<tot*Ksm(m,mm-2)%mm; return 0; }