P1446-[HNOI2008]Cards【Burnside引理,dp】

正题

题目链接:https://www.luogu.com.cn/problem/P1446


题目大意

三个颜色的一些东西排在一起,给 m m m种置换,求本质不同的染色方案数。


解题思路

B u r n s i d e Burnside Burnside引理:置换集合 G G G时本质不同的序列方案等于 ∑ x ∈ G c ( x ) ∣ G ∣ \frac{\sum_{x\in G}c(x)}{|G|} ∣G∣∑x∈G​c(x)​, c ( x ) c(x) c(x)表示置换 x x x中的不动点个数。

也就是每个循环中的颜色都相同,可以把每个循环视为一个物品,然后放入容量为 r , g , b r,g,b r,g,b的背包里的方案数,求解即可。

时间复杂度 O ( r ∗ g ∗ b ∗ m ) O(r*g*b*m) O(r∗g∗b∗m)


c o d e code code

#include<cstdio>
#include<cstring>
#include<algorithm>
#define ll long long
using namespace std;
ll r,b,g,m,p,n,tot,ans;
ll siz[81],f[21][21][21],y[81];
bool v[81];
ll power(ll x,ll b){
	ll ans=1;
	while(b){
		if(b&1)ans=ans*x%p;
		x=x*x%p;b>>=1;
	}
	return ans;
}
ll solve(){
	memset(f,0,sizeof(f));
	memset(v,0,sizeof(v));
	tot=0;
	for(ll i=1;i<=n;i++){
		if(v[i])continue;
		siz[++tot]=0;ll x=i;
		while(!v[x]){
			siz[tot]++;
			v[x]=1;x=y[x];
		}
	}
	f[0][0][0]=1;
	for(ll x=1;x<=tot;x++)
		for(ll i=r;i>=0;i--)
			for(ll j=g;j>=0;j--)
				for(ll k=b;k>=0;k--){
					if(i>=siz[x])(f[i][j][k]+=f[i-siz[x]][j][k])%=p;
					if(j>=siz[x])(f[i][j][k]+=f[i][j-siz[x]][k])%=p;
					if(k>=siz[x])(f[i][j][k]+=f[i][j][k-siz[x]])%=p;
				}
	return f[r][g][b];
}
int main()
{
	scanf("%lld%lld%lld%lld%lld",&r,&g,&b,&m,&p);
	n=r+b+g;
	for(ll i=1;i<=n;i++)y[i]=i;
	ans=solve();
	for(ll i=1;i<=m;i++){
		for(ll j=1;j<=n;j++)
			scanf("%lld",&y[j]);
		(ans+=solve())%=p;
	}
	printf("%lld\n",ans*power(m+1,p-2)%p);
	return 0;
}
上一篇:越狱(快速幂)


下一篇:1034 有理数四则运算 (20分)