bzoj1004 Polya计数

burnside引理:ans=sum(x(f)=置换f的不动点数)/(|G|=置换数);

置换f的不动点:如果方案x经过置换f后仍然不变,它就是置换f的一个不动点。

polya计数:将置换分解成轮换后直接推不动点数。

以本题为例,分解成轮换后,不动点满足:1.每个轮换内部所有点颜色相同。2.对于整个置换而言,sum1=a,sum2=b,sum3=c。

dp即可。

#include<bits/stdc++.h>
using namespace std;
#define rep(x,y,z) for (int x=y; x<=z; x++)
#define downrep(x,y,z) for (int x=y; x>=z; x--)
#define ms(x,y,z) memset(x,y,sizeof(z))
#define LL long long
#define repedge(x,y) for (int x=hed[y]; ~x; x=edge[x].nex)
inline int read(){
	int x=0; int w=0; char ch=0;
	while (ch<'0' || ch>'9') w|=ch=='-',ch=getchar();
	while (ch>='0' && ch<='9') x=(x<<3)+(x<<1)+(ch^48),ch=getchar();
	return w? -x:x;
}
LL P;
void ex_gcd(LL a,LL b,LL c,LL &x,LL &y){
	if (!a){ x=0; y=c/b; return; }
	if (!b){ y=0; x=c/a; return; }
	ex_gcd(b,a%b,c,y,x);
	y-=(a/b)*x;
}
LL inv(LL t){
	t%=P; LL x,y; ex_gcd(t,P,1,x,y); return (x%P);
}
const int N=65;
const int A=25;
int nedge,hed[N],vis[N],d[N],f[N][A][A][A];
struct Edge{ int to,nex; }edge[N<<1];
void addedge(int a,int b){
    edge[nedge].to=b; edge[nedge].nex=hed[a]; hed[a]=nedge++;
}
int dfs(int k){
	int res=1; vis[k]=1;
	repedge(i,k){ int v=edge[i].to; 
	   if (!vis[v]) res+=dfs(v); }
	return res;
}
int a,b,c,m;
int main(){
	a=read(); b=read(); c=read(); m=read(); P=read(); int n=a+b+c; LL ans=0;
	rep(i,0,m){
		int tot=0; if (i){ nedge=0; rep(j,1,n) hed[j]=-1; rep(j,1,n) { int x=read(); addedge(x,j); }
		rep(j,1,n) vis[j]=0; tot=0; rep(j,1,n) if (!vis[j]) d[++tot]=dfs(j); }
		else{ tot=n; rep(j,1,n) d[j]=1; }
		rep(j,0,tot-1) rep(t1,0,a) rep(t2,0,b) rep(t3,0,c) f[j][t1][t2][t3]=0; f[0][0][0][0]=1;
		rep(j,0,tot-1) rep(t1,0,a) rep(t2,0,b) rep(t3,0,c){
			if (t1+d[j+1]<=a) f[j+1][t1+d[j+1]][t2][t3]=(f[j+1][t1+d[j+1]][t2][t3]+f[j][t1][t2][t3])%P;
			if (t2+d[j+1]<=b) f[j+1][t1][t2+d[j+1]][t3]=(f[j+1][t1][t2+d[j+1]][t3]+f[j][t1][t2][t3])%P;
		    if (t3+d[j+1]<=c) f[j+1][t1][t2][t3+d[j+1]]=(f[j+1][t1][t2][t3+d[j+1]]+f[j][t1][t2][t3])%P;
		}
		ans=(ans+f[tot][a][b][c])%P;
	}
	ans=(ans*inv(m+1))%P; ans=(ans%P+P)%P;
	printf("%lld\n",ans); return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值