题目描述
题解
推荐一个课件:http://wenku.baidu.com/link?url=iT9AF_F7nlm5ChUKKgVHCTZXJJIlRvmqxebDvwClLNWVVz84HtZT6Z7Clmo-ABxqJfct5I6bOnEf4jiaMqgke9ZEJMCPHRi2-KEq-eQQSCS 这里解释了Burnside引理和Polya定理
转自黄学长的题解:
Burnside定理:有m个置换k种颜色,所有本质不同的染色方案数就是每种置换的不变元素的个数的平均数。所谓不变元素就是一种染色方案经过置换变换后和没变化之前一样。所以现在就是需要求出不变元素,同时还要满足各种颜色数量的限制。置换的循环在不变元素中一定是一个颜色,然后可以求一个三维的01背包的方案数。而最后的除法需要利用扩展欧几里得求乘法的逆元。
代码
#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
const int max_n=25;
const int max_m=65;
const int max_N=max_n*3;
int n,m,sr,sb,sg,Mod,x,ans;
int a[max_m][max_N],sum[max_N],f[max_n][max_n][max_n];
bool used[max_N];
inline int dp(int x)
{
int p,cnt=0;
memset(used,0,sizeof(used));
for (int i=1;i<=n;++i)
if (!used[i])
{
p=i;
sum[++cnt]=1;
used[p]=true;
while (!used[a[x][p]])
{
sum[cnt]++;
used[a[x][p]]=true;
p=a[x][p];
}
}
for (int i=0;i<=sr;++i)
for (int j=0;j<=sb;++j)
for (int k=0;k<=sg;++k)
f[i][j][k]=0;
f[0][0][0]=1;
for (int h=1;h<=cnt;++h)
for (int i=sr;i>=0;--i)
for (int j=sb;j>=0;--j)
for (int k=sg;k>=0;--k)
{
if (i>=sum[h]) f[i][j][k]=(f[i][j][k]+f[i-sum[h]][j][k])%Mod;
if (j>=sum[h]) f[i][j][k]=(f[i][j][k]+f[i][j-sum[h]][k])%Mod;
if (k>=sum[h]) f[i][j][k]=(f[i][j][k]+f[i][j][k-sum[h]])%Mod;
}
return f[sr][sb][sg];
}
inline int fast_pow(int a,int p)
{
int ans=1;
for (;p;p>>=1,a=(a*a)%Mod)
if (p&1)
ans=(ans*a)%Mod;
return ans;
}
int main()
{
scanf("%d%d%d%d%d",&sr,&sb,&sg,&m,&Mod);
n=sr+sb+sg;
for (int i=1;i<=m;++i)
for (int j=1;j<=n;++j)
scanf("%d",&a[i][j]);
m++;
for (int i=1;i<=n;++i) a[m][i]=i;
for (int i=1;i<=m;++i)
ans=(ans+dp(i))%Mod;
x=fast_pow(m,Mod-2);
ans=(ans*x)%Mod;
printf("%d\n",ans);
}
总结
注意一下整数群和置换群的区别。