群论第一题。
发现这题也是有颜色个数限制的,所以不能用$Polya$,只能用$Burnside$
$L={frac{1}{|G|}}{sum_{i=1}^{m}{D(a_{i})}}$
先$dfs$出每个循环节长度,每个循环节颜色需要一样,$dp$就好了。
1 #include<cstdio> 2 #include<cstring> 3 #include<iostream> 4 #include<algorithm> 5 #include<cmath> 6 #define N 105 7 using namespace std; 8 int n,m,mod,na,nb,nc,nn,ans; 9 int num[N],sum[N],f[N][N][N],fa[N],fac[N]; 10 bool vis[N]; 11 void dfs(int x,int now){ 12 vis[x]=1;num[now]++; 13 if(!vis[fa[x]])dfs(fa[x],now); 14 } 15 int qp(int a,int b){ 16 int c=1; 17 while(b){ 18 if(b&1)c=c*a%mod; 19 a=a*a%mod;b>>=1; 20 } 21 return c; 22 } 23 int C(int a,int b){ 24 if(b<0||b>a)return 0; 25 if(!b||a==b)return 1; 26 return fac[a]*qp(fac[b],mod-2)%mod*qp(fac[a-b],mod-2)%mod; 27 } 28 int main(){ 29 scanf("%d%d%d%d%d",&na,&nb,&nc,&m,&mod); 30 n=na+nb+nc; 31 fac[0]=1; 32 for(int i=1;i<=60;i++)fac[i]=fac[i-1]*i%mod; 33 for(int t=1;t<=m;t++){ 34 for(int i=1;i<=n;i++) 35 scanf("%d",&fa[i]); 36 memset(vis,0,sizeof vis); 37 memset(num,0,sizeof num); 38 memset(f,0,sizeof f); 39 nn=0; 40 for(int i=1;i<=n;i++) 41 if(!vis[i]){ 42 dfs(i,++nn); 43 sum[nn]=sum[nn-1]+num[nn]; 44 } 45 f[0][0][0]=1; 46 for(int i=1;i<=nn;i++){ 47 for(int j=0;j<=na;j++){ 48 if(j>sum[i-1])break; 49 for(int k=0;k<=nb;k++){ 50 if(j+k>sum[i-1])break; 51 int l=sum[i-1]-j-k; 52 if(l>nc)break; 53 if(j+num[i]<=na)f[i][j+num[i]][k]+=f[i-1][j][k]; 54 if(k+num[i]<=nb)f[i][j][k+num[i]]+=f[i-1][j][k]; 55 if(l+num[i]<=nc)f[i][j][k]+=f[i-1][j][k]; 56 } 57 } 58 } 59 ans+=f[nn][na][nb]; 60 } 61 (ans+=C(n,na)*C(n-na,nb))%=mod; 62 (ans*=qp(m+1,mod-2))%=mod; 63 printf("%d ",ans); 64 return 0; 65 }