【题意分析】
给N个元素染色,可以在定置换群的作用下互相转化的染色方案算相同的,问本质不同的染色方案数。
【解题思路】
引理:Burnside定理
设集合S=[1,n]∩N,记等价类数为L,给定S上的置换群G。
Zk (k不动置换类):若k是S中某个元素,G中使k保持不变的置换的全体,记以Zk,叫做G中使k保持不动的置换类,简称k不动置换类。
C(π)(置换n的不动点全集):对于一个置换π∈G,及a∈X,若π(a)=a,则称a为π的不动点。π的不动点的全体记为C(π)。
有定理:L=1/|G|*∑|Zk|(k∈S)=1/|G|*Σ|C(n)|(n∈G)。
所以,我们只要分别计算G中每个置换的不动点数,就可以计算出等价类数。外层复杂度O(m)。
考虑染色,对于每个置换,在同一个置换环中的元素必定染成同色,才能保证集合range(n)经过置换后染色方案不变,所以可以用三维背包来计算方案数。内层复杂度O(SrSgSb+n)。
总复杂度O(n^2+nSrSgSb)。
【参考代码】
1 #include <cmath> 2 #include <cstdio> 3 #define REP(I,start,end) for(int I=(start);I<=(end);I++) 4 #define PER(I,start,end) for(int I=(start);I>=(end);I--) 5 #define REPs(I,start,end,step) for(int I=(start);I<=(end);I+=(step)) 6 #define PERs(I,start,end,step) for(int I=(start);I>=(end);I-=(step)) 7 using namespace std; 8 typedef unsigned short US; 9 typedef unsigned long UL; 10 typedef long long LL; 11 typedef unsigned long long ULL; 12 inline int getint() 13 { 14 char ch=getchar(); 15 while((ch<'0'||ch>'9')&&ch!='-') 16 ch=getchar(); 17 int result=0; 18 bool impositive=ch=='-'; 19 if(impositive) 20 ch=getchar(); 21 while(ch>='0'&&ch<='9') 22 { 23 result=(result<<3)+(result<<1)+ch-'0'; 24 ch=getchar(); 25 } 26 return impositive?-result:result; 27 } 28 inline int putint(int n) 29 { 30 int result=1; 31 char* sav=new char[20]; 32 bool impositive=n<0; 33 if(impositive) 34 { 35 putchar('-'); 36 n=-n; 37 } 38 sav[0]=n%10+'0'; 39 while(n/=10) 40 sav[result++]=n%10+'0'; 41 PER(i,result-1,0) 42 putchar(sav[i]); 43 delete []sav; 44 return result+impositive; 45 } 46 inline LL getLL() 47 { 48 char ch=getchar(); 49 while((ch<'0'||ch>'9')&&ch!='-') 50 ch=getchar(); 51 LL result=0ll; 52 bool impositive=ch=='-'; 53 if(impositive) 54 ch=getchar(); 55 while(ch>='0'&&ch<='9') 56 { 57 result=(result<<3)+(result<<1)+ch-'0'; 58 ch=getchar(); 59 } 60 return impositive?-result:result; 61 } 62 inline int putLL(LL n) 63 { 64 int result=1; 65 char* sav=new char[20]; 66 bool impositive=n<0; 67 if(impositive) 68 { 69 putchar('-'); 70 n=-n; 71 } 72 sav[0]=n%10+'0'; 73 while(n/=10) 74 sav[result++]=n%10+'0'; 75 PER(i,result-1,0) 76 putchar(sav[i]); 77 delete []sav; 78 return result+impositive; 79 } 80 template<typename integer> inline int read_int(integer &n) 81 { 82 char ch=getchar(); 83 while((ch<'0'||ch>'9')&&ch!='-') 84 ch=getchar(); 85 int result=n=integer(0); 86 bool impositive=ch=='-'; 87 if(impositive) 88 ch=getchar(); 89 while(ch>='0'&&ch<='9') 90 { 91 n=(n<<3)+(n<<1)+integer(ch-'0'); 92 result++; 93 ch=getchar(); 94 } 95 if(impositive) 96 { 97 n=-n; 98 result++; 99 } 100 return result; 101 } 102 template<typename integer> inline int write_int(integer n) 103 { 104 int result=1; 105 char* sav=new char[20]; 106 bool impositive=n<0; 107 if(impositive) 108 { 109 putchar('-'); 110 n=-n; 111 } 112 sav[0]=n%10+'0'; 113 while(n/=10) 114 sav[result++]=n%10+'0'; 115 PER(i,result-1,0) 116 putchar(sav[i]); 117 delete []sav; 118 return result+impositive; 119 } 120 template<typename integer> inline integer sqr(integer n) 121 { 122 return n*n; 123 } 124 template<typename base_type,typename exp_type> inline base_type PowerMod(base_type Base,exp_type Exp,base_type Mod) 125 { 126 bool* sav=new bool[int(log(Exp)/log(2))+1]; 127 int tot=0; 128 base_type result=base_type(1),baser=Base%Mod; 129 exp_type tmp=Exp; 130 while(tmp) 131 { 132 sav[tot++]=tmp&1; 133 tmp>>=1; 134 } 135 while(tot) 136 { 137 result=sqr(result)%Mod; 138 if(sav[--tot]) 139 result=result*baser%Mod; 140 } 141 delete []sav; 142 return result; 143 } 144 //====================================Header Template=================================== 145 #include <cstring> 146 bool used[100]; 147 int sr,sb,sg,n,p,trans[100],cnt[100],f[30][30][30]; 148 inline int mod_reverse(int _n,int _p) 149 { 150 return PowerMod(_n,_p-2,_p); 151 } 152 inline int DP() 153 { 154 memset(f,0,sizeof(f)); 155 memset(used,0,sizeof(used)); 156 int group=0; 157 REP(i,1,n) 158 if(!used[i]) 159 { 160 used[i]=true; 161 int j=trans[i],tot=1; 162 while(!used[j]) 163 { 164 used[j]=true; 165 tot++; 166 j=trans[j]; 167 } 168 cnt[++group]=tot; 169 } 170 f[0][0][0]=1; 171 REP(g,1,group) 172 PER(i,sr,0) 173 PER(j,sb,0) 174 PER(k,sg,0) 175 { 176 if(i>=cnt[g]) 177 (f[i][j][k]+=f[i-cnt[g]][j][k])%=p; 178 if(j>=cnt[g]) 179 (f[i][j][k]+=f[i][j-cnt[g]][k])%=p; 180 if(k>=cnt[g]) 181 (f[i][j][k]+=f[i][j][k-cnt[g]])%=p; 182 } 183 return f[sr][sb][sg]; 184 } 185 int main() 186 { 187 sr=getint(); 188 sb=getint(); 189 sg=getint(); 190 int m=getint(); 191 p=getint(); 192 n=sr+sb+sg; 193 int ans=0; 194 REP(i,1,m) 195 { 196 REP(j,1,n) 197 trans[j]=getint(); 198 (ans+=DP())%=p; 199 } 200 REP(i,1,n) 201 trans[i]=i; 202 (ans+=DP())%=p; 203 putint(ans*mod_reverse(m+1,p)%p); 204 return 0; 205 }