题解: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;
}