bzoj 1004 Cards & poj 2409 Let it Bead —— 置换群
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=1004
关于置换群:https://www.cnblogs.com/nietzsche-oier/p/6883880.html
https://files-cdn.cnblogs.com/files/HocRiser/Burnside.pdf
原来 burnside 引理中的“不动点”是指一种不变化的方案啊;
这道题就用 burnside 引理,但给出的 m 个置换还不是置换群,需要再加一个单位元,即 \( a[i] = i \) 的置换;
用三维DP求出每种置换的“不动点”个数,枚举可以通过记录总数而减少一维。
代码如下:
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; typedef long long ll; int const xn=65,xm=25; int n,m,sr,sb,sg,a[xn],f[xm][xm][xm],mod,tot; bool vis[xn]; int rd() { int ret=0,f=1; char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=0; ch=getchar();} while(ch>='0'&&ch<='9')ret=ret*10+ch-'0',ch=getchar(); return f?ret:-ret; } ll pw(ll a,int b) { ll ret=1; for(;b;b>>=1,a=(a*a)%mod)if(b&1)ret=(ret*a)%mod; return ret; } int upt(int x){while(x>=mod)x-=mod; while(x<0)x+=mod; return x;} void dfs(int x) { tot++; vis[x]=1; if(!vis[a[x]])dfs(a[x]); } int main() { sr=rd(); sb=rd(); sg=rd(); m=rd(); mod=rd(); n=sr+sb+sg; m++; for(int i=1;i<=m;i++) { memset(vis,0,sizeof vis); memset(f,0,sizeof f); f[0][0][0]=1;// if(i==m)for(int j=1;j<=n;j++)a[j]=j; else for(int j=1;j<=n;j++)a[j]=rd(),vis[j]=0; tot=0; int res=0; for(int j=1;j<=n;j++) { if(vis[j])continue; tot=0; dfs(j); res+=tot; for(int j=sr;j>=0;j--) for(int k=sb;k>=0;k--) //for(int l=sg;l>=0;l--) { int l=res-j-k; if(l<0)continue; if(j>=tot)f[j][k][l]=upt(f[j][k][l]+f[j-tot][k][l]); if(k>=tot)f[j][k][l]=upt(f[j][k][l]+f[j][k-tot][l]); if(l>=tot)f[j][k][l]=upt(f[j][k][l]+f[j][k][l-tot]); } } } printf("%lld\n",(ll)f[sr][sb][sg]*pw(m,mod-2)%mod); return 0; }
题目:http://poj.org/problem?id=2409
Polya 定理裸题;
gcd 可以从模的剩余系的角度来看;
注意加上翻转后有 2n 个置换。
代码如下:
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; int const xn=40; int n,m; int gcd(int a,int b){return b?gcd(b,a%b):a;} int pw(int a,int b) { int ret=1; for(;b;b>>=1,a=a*a)if(b&1)ret=ret*a; return ret; } int main() { while(1) { scanf("%d%d",&m,&n); if(!m&&!n)return 0; int ans=0; for(int i=1;i<=n;i++)ans+=pw(m,gcd(n,i)); if(n%2)ans+=n*pw(m,n/2+1); else ans+=n/2*pw(m,n/2)+n/2*pw(m,n/2+1); printf("%d\n",ans/2/n);//2n } return 0; }