您的位置:首页 > 其它

[学习笔记]等价类计数&Polya定理 bzoj1004 [HNOI2008]Cards

2018-01-30 21:49 423 查看
论述证明等部分略去,说实在的我也不是很懂。

直接说结论。记f是一个置换,然后有一个置换群,群的概念自行搜索,记C(f)表示在置换f作用下不变的有多少种,那么染色的方案数等于所有C的和的平均数。这个结论没有问题,问题是如何计算C。

如果对染色没有限制,那么C=(颜色数量)的(置换中环的个数)次方。

如果有限制,例如bzoj1004,可以用dp算,算法显然不赘述。

代码:

#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#define rep(i,s,t) for(int i=s;i<=t;i++)
#define per(i,t,s) for(int i=t;i>=s;i--)
#define S 23
#define N S*3
#define inv(n) fast_pow(n,p-2,p)
using namespace std;
int dp[S][S][S],A,B,C,n,m,p,ans;
int fast_pow(int n,int k,int p)
{
if(k==0) return 1;if(k==1) return n%p;
int ans=fast_pow(n,k>>1,p);ans=ans*ans%p;
if(k&1) ans=ans*n%p;return ans;
}
int to
,cnt,t
,r;bool vis
;
int main()
{
scanf("%d%d%d%d%d",&A,&B,&C,&m,&p),n=A+B+C,r=++m;
while(m--)
{
if(m) for(int i=1;i<=n;i++) scanf("%d",&to[i]);
else for(int i=1;i<=n;i++) to[i]=i;
memset(vis,false,sizeof(vis)),cnt=0;
for(int i=1,x;i<=n;i++)
if(!vis[i])
{
x=i,t[++cnt]=1,vis[x]=true;
while(!vis[to[x]]) vis[x=to[x]]=true,t[cnt]++;
}
dp[0][0][0]=1;
//      printf("cnt=%d : ",cnt);rep(i,1,cnt) cout<<t[i]<<" ";cout<<endl;
rep(i,1,cnt) per(a,A,0) per(b,B,0) per(c,C,0)
{
dp[a][b][c]=0;
if(a>=t[i]) dp[a][b][c]+=dp[a-t[i]][b][c];
if(b>=t[i]) dp[a][b][c]+=dp[a][b-t[i]][c];
if(c>=t[i]) dp[a][b][c]+=dp[a][b][c-t[i]];
dp[a][b][c]%=p;
}
ans+=dp[A][B][C];
}
return !printf("%d\n",ans%p*inv(r)%p);
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: