终于是把这题过了。
首先,一个赤裸裸的置换在那,显然不是Burnside就是Pólya。
这题由于有三种颜色且颜色数是有限的,Pólya是没法用了,上Burnside。
Burnside是说,真正意义上不变的染色方案数=Σ(每种置换下不变的染色方案数)/(置换总数)
求出每种置换下不变的染色方案数便显得很重要,这里便需要特殊到这道题了。
对于每一种置换,我们求出其循环节(超像Pólya!),显然的,每个循环节必须染同样的颜色。
接下来,就能够通过一个DP将整个分子求出。
而分母,由于是除法,所以需要用到乘法逆元,又因为这里保证p为素数,所以可以直接用快速幂来求逆元。
调试小结:
1.DP时不能从小往大DP(或者写4维的),会重复计算。
1 /************************************************************** 2 Problem: 1004 3 User: zhuohan123 4 Language: C++ 5 Result: Accepted 6 Time:152 ms 7 Memory:1380 kb 8 ****************************************************************/ 9 10 #include <iostream> 11 #include <cstdio> 12 #include <cstring> 13 using namespace std; 14 int sr,sg,sb,m,p,n; 15 inline void add(int &a,int b){a=(a+b)%p;} 16 int z[100],s[100],snum; 17 bool ha[100]; 18 int f[30][30][30]; 19 int calc() 20 { 21 memset(f,0,sizeof f); 22 memset(ha,0,sizeof ha); 23 memset(s,0,sizeof s); 24 snum=0; 25 for(int i=1;i<=n;i++) 26 if(!ha[i]) 27 { 28 snum++; 29 for(int j=i;!ha[j];j=z[j])ha[j]=true,s[snum]++; 30 } 31 f[0][0][0]=1; 32 for(int i=1;i<=snum;i++) 33 for(int r=sr;r>=0;r--) 34 for(int g=sg;g>=0;g--) 35 for(int b=sb;b>=0;b--) 36 { 37 if(r>=s[i])add(f[r][g][b],f[r-s[i]][g][b]); 38 if(g>=s[i])add(f[r][g][b],f[r][g-s[i]][b]); 39 if(b>=s[i])add(f[r][g][b],f[r][g][b-s[i]]); 40 } 41 42 return f[sr][sg][sb]; 43 } 44 inline int sqr(int a){return a*a;} 45 int exp(int a,int b,int p) 46 { 47 return b?sqr(exp(a,b/2,p))%p*((b&1)?a:1)%p:1; 48 } 49 int main(int argc, char *argv[]) 50 { 51 scanf("%d%d%d%d%d",&sr,&sg,&sb,&m,&p); 52 n=sr+sg+sb; 53 int ans=0; 54 for(int time=1;time<=m;time++) 55 { 56 for(int i=1;i<=n;i++)scanf("%d",&z[i]); 57 add(ans,calc()); 58 } 59 for(int i=1;i<=n;i++)z[i]=i; 60 add(ans,calc()); 61 ans*=exp(m+1,p-2,p);ans%=p; 62 printf("%d ",ans); 63 return 0; 64 }