【题意分析】

  给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 }
View Code