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;
}

 

posted @ 2018-12-03 21:56  Zinn  阅读(142)  评论(0编辑  收藏  举报