标签:bzoj burnside引理 polya计数 hnoi
【解析】Burnside引理+背包dp+乘法逆元
[Analysis]
这道题卡了好久,就是没想懂置换跟着色是不一样的。
根据burnside引理,在一个置换群作用下不等价类的个数为每个置换作用下不动点个数的平均数。
在这道题中:
置换的对象 ——
每个状态,标号为1—N(这里的N不是题目的N,而是状态的个数)。
不动点 ——
前后染色状态完全相同的状态的个数。
所以就是求经过变换后前后状态完全相同的个数。
[Sum]
Burnside引理几个注意的地方
[1]什么是Burnside引理?
[2]置换的对象是什么?
[3]不动点意味着什么?
[4]着色变换不是置换。
[Code]
<span style="font-size:18px;">/**************************************************************
Problem: 1004
User: y20070316
Language: C++
Result: Accepted
Time:328 ms
Memory:2164 kb
****************************************************************/
#include <cstdio>
#include <cstring>
#include <cstdlib>
using namespace std;
const int N=70;
int Sr,Sb,Sg,n,m,p; //Basic
int map[N][N],d[N],v[N],cnt; //Substitution
int f[N][N][N]; //Damatic Programming
int res; //Answer
inline int read(void)
{
int s=0,f=1; char c=getchar();
for (;c<'0'||c>'9';c=getchar());
for (;'0'<=c&&c<='9';c=getchar()) s=s*10+c-'0';
return s*f;
}
void init(void)
{
Sr=read(),Sb=read(),Sg=read(),n=Sr+Sb+Sg;
m=read(),p=read();
for (int i=1;i<=m;i++)
for (int j=1;j<=n;j++) map[i][j]=read();
m++; for (int j=1;j<=n;j++) map[m][j]=j;
}
void work(void)
{
for (int i=1;i<=m;i++)
{
cnt=0; memset(v,0,sizeof v);
memset(d,0,sizeof d);
for (int j=1;j<=n;j++)
if (!v[j])
{
v[j]=d[++cnt]=1;
for (int k=map[i][j];k^j;k=map[i][k])
v[k]=1,d[cnt]++;
}
memset(f,0,sizeof f); f[0][0][0]=1;
for (int i=1;i<=cnt;i++)
for (int j=Sr;j>=0;j--)
for (int k=Sb;k>=0;k--)
for (int q=Sg;q>=0;q--)
{
f[j][k][q]=0;
if (j>=d[i]) f[j][k][q]=(f[j][k][q]+f[j-d[i]][k][q])%p;
if (k>=d[i]) f[j][k][q]=(f[j][k][q]+f[j][k-d[i]][q])%p;
if (q>=d[i]) f[j][k][q]=(f[j][k][q]+f[j][k][q-d[i]])%p;
}
res=(res+f[Sr][Sb][Sg])%p;
}
}
int mi(int i,int j)
{
if (!j) return 1;
int s=mi(i,j>>1);
s=s*s%p;
if (j&1) s=s*i%p;
return s;
}
void print(void)
{
int inv=mi(m,p-2);
res=res*inv%p;
printf("%d\n",(res+p)%p);
}
int main(void)
{
init();
work();
print();
return 0;
}</span>版权声明:本文为博主原创文章,未经博主允许不得转载。
标签:bzoj burnside引理 polya计数 hnoi
原文地址:http://blog.csdn.net/u013598409/article/details/47010555