题目大意:给定n张卡牌和m个置换,求等价类个数
数据保证这m个置换加上自身置换后构成一个置换群
BZOJ坑爹0.0 这么重要的条件不给出来尼玛怎么做
Burnside引理……昨晚为了做这题硬啃了一晚上白书0.0 都快啃吐了0.0
Burnside引理:一个置换群下的等价类个数等于所有置换的不动点个数的平均值
没有接触过群论的建议去啃白书…… 网上的东西看不懂的
最后那个除法要用乘法逆元 我懒得写EXGCD写了费马小定理0.0
#include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #define M 70 using namespace std; int r,g,b,m,n,p,ans; int a[M],stack[M],top; int f[21][21][21]; void DFS(int x) { stack[top]++; int temp=a[x]; a[x]=0; if(a[temp]) DFS(temp); } int DP() { int i,j,k; memset(f,0,sizeof f);f[0][0][0]=1; while(top) { for(i=r;~i;i--) for(j=g;~j;j--) for(k=b;~k;k--) { if(i>=stack[top]) f[i][j][k]+=f[i-stack[top]][j][k]; if(j>=stack[top]) f[i][j][k]+=f[i][j-stack[top]][k]; if(k>=stack[top]) f[i][j][k]+=f[i][j][k-stack[top]]; f[i][j][k]%=p; } stack[top--]=0; } return f[r][g][b]; } int KSM(int x,int y) { int re=1; while(y) { if(y&1)re*=x,re%=p; x*=x,x%=p; y>>=1; } return re; } int main() { int i,j; cin>>r>>g>>b>>m>>p; n=r+g+b; for(i=1;i<=m;i++) { for(j=1;j<=n;j++) scanf("%d",&a[j]); for(j=1;j<=n;j++) if(a[j]) ++top,DFS(j); ans+=DP(),ans%=p; } for(j=1;j<=n;j++) a[j]=j; for(j=1;j<=n;j++) if(a[j]) ++top,DFS(j); ans+=DP(),ans%=p; ans*=KSM(m+1,p-2),ans%=p; cout<<ans<<endl; }
BZOJ 1004 HNOI2008 Cards Burnside引理
原文地址:http://blog.csdn.net/popoqqq/article/details/40180559