【Burnside定理/置换】[HNOI2008][HYSBZ/BZOJ1004]Cards

来源:互联网 发布:鲸蜡醇乙基己酸酯 知乎 编辑:程序博客网 时间:2024/06/10 05:03

写在前面

如果你不知道知道置换,或者想要一种更快的方法,请前往【组合数学】[HNOI2008][HYSBZ/BZOJ1004]Cards.

题目链接

分析

根据Burnside定理,用D(aj) 表示在置换aj下不变的元素的个数。L表示本质不同的方案数,G表示置换群

L=1|G|i=1|G|D(aj)

计算D(aj)可以用DP;
每一个置换由T个循环节组成,每个循环节的颜色显然应该一样。我们可以处理出循环节。
用f[j][u][x][y][z]表示第j个置换第u个循环节染了x个红色,y个蓝色,z个绿色纸牌
fj,u,I,j,k=fj,u1,ia[u],j,k+fj,u1,i,ja[u],k+fj,u1,I,j,ka[u]

最后要除以G,但是在前面的计算过程中已经mod p这么办?求逆元呀。
看看这里

#include<cstdio>#include<algorithm>#include<cstring>#define MAXN 60#define MAXM 60#define MAXC 20using namespace std;int sr,sb,sg,m,p,x[MAXM+10][MAXM+10],f[MAXN+2][MAXC+2][MAXC+2][MAXC+2],ans,n;void Read(int &x){    char c;    while(c=getchar(),c!=EOF)        if(c>='0'&&c<='9'){            x=c-'0';            while(c=getchar(),c>='0'&&c<='9')                x=x*10+c-'0';            ungetc(c,stdin);            return;        }}void read(){    Read(sr),Read(sb),Read(sg),Read(m),Read(p);    n=sr+sb+sg;    int i,j;    for(i=1;i<=m;i++)        for(j=1;j<=n;j++)            Read(x[i][j]);}bool vis[MAXN+10];int quick_pow(int a,int b){    int ret=1;    while(b){        if(b&1)            ret=ret*a%p;        a=a*a%p;        b>>=1;    }    return ret;}void solve(){    int i,cnt,a[MAXN+10],u,xx,y,z,j;    m++;    for(i=1;i<=n;i++)        x[m][i]=i;    for(i=1;i<=m;i++){        memset(a,0,sizeof a);        cnt=0;        memset(vis,0,sizeof vis);        for(j=1;j<=n;j++)            if(!vis[j]){                cnt++;                while(!vis[j]){                    vis[j]=1,a[cnt]++;                    j=x[i][j];                }            }        memset(f,0,sizeof f);        f[0][0][0][0]=1;        for(u=1;u<=cnt;u++){            for(xx=0;xx<=sr;xx++)                for(y=0;y<=sb;y++)                    for(z=0;z<=sg;z++){                        if(xx>=a[u])                            f[u][xx][y][z]+=f[u-1][xx-a[u]][y][z];                        if(y>=a[u])                            f[u][xx][y][z]+=f[u-1][xx][y-a[u]][z];                        if(z>=a[u])                            f[u][xx][y][z]+=f[u-1][xx][y][z-a[u]];                        f[u][xx][y][z]%=p;                    }            ans=(ans+f[cnt][sr][sb][sg])%p;        }    }    ans=ans*quick_pow(m,p-2)%p;}int main(){    read();    solve();    printf("%d\n",ans);}
0 0
原创粉丝点击