BZOJ1004: [HNOI2008]Cards

三维01背包算出在每一个置换下不变的染色方案数,Burnside引理计算答案。

PS:数据太水所以只算恒等置换也是可以过的。

#include<bits/stdc++.h>
using namespace std;
int n,m,p,x,y,z;
bool u[61];
int f[21][21][21],s[61],v[61];
int power(int u,int v){
	int d=1;
	for(;v;v>>=1){
		if(v&1)
			d=d*u%p;
		u=u*u%p;
	}
	return d;
}
void add(int& u,int v){
	u=(u+v)%p;
}
int main(){
	scanf("%d%d%d%d%d",&x,&y,&z,&m,&p);
	n=x+y+z;
	int ans=1;
	for(int i=1;i<=n;++i)
		ans=ans*i%p;
	for(int i=1;i<=x;++i)
		ans=ans*power(i,p-2)%p;
	for(int i=1;i<=y;++i)
		ans=ans*power(i,p-2)%p;
	for(int i=1;i<=z;++i)
		ans=ans*power(i,p-2)%p;
	for(int t=0;t!=m;++t){
		for(int i=1;i<=n;++i)
			scanf("%d",s+i);
		memset(u,0,sizeof u);
		int cnt=0;
		for(int i=1;i<=n;++i)
			if(!u[i]){
				int k=u[i]=1;
				for(int j=s[i];j!=i;j=s[j])
					k+=u[j]=1;
				v[cnt++]=k;
			}
		memset(f,0,sizeof f);
		f[0][0][0]=1;
		for(int a=0;a!=cnt;++a)
			for(int i=x;~i;--i)
				for(int j=y;~j;--j)
					for(int k=z;~k;--k){
						if(i>=v[a])
							add(f[i][j][k],f[i-v[a]][j][k]);
						if(j>=v[a])
							add(f[i][j][k],f[i][j-v[a]][k]);
						if(k>=v[a])
							add(f[i][j][k],f[i][j][k-v[a]]);
					}
		add(ans,f[x][y][z]);
	}
	printf("%d\n",ans*power(m+1,p-2)%p);
}
posted @ 2016-05-15 19:37  f321dd  阅读(134)  评论(0编辑  收藏  举报