• 埋锅。。。BZOJ1004-置换群+burnside定理+


      看这道题时当时觉得懵逼。。。这玩意完全看不懂啊。。。什么burnside。。。难受。。。

      于是去看了点视频和资料,大概懂了置换群和burnside定理,亦步亦趋的懂了别人的代码,然后慢慢的打了出来。。。高兴的一匹。

    回归正题啊,这个题如果大家不懂置换群的概念。。。是很难看的懂的,M种洗牌,代表了M种置换,加上自己本身一种,构成看M+1种置换,如果一种可以通过任意的洗牌法洗成另一种的看成一类(这就是等价类的定义),问有多少种染色方法???

    这道题很明显嘛,就是算等价类的数目,这个需要用到burnside定理。。。

    我们可以求所有循环长度为1的循环的个数,用burnside来求

    对于置换i,求出它的循环节,每个循环节必须染成同一个颜色,但是对总数有限制

    f[i][j][k]表示用i个红色,j个蓝色,k个绿色的方案数

    把每个循环节视为一个物品,权值为长度。

    f[i][j][k]=f[i-d[p]][j][k]+f[i][j-d[p]][k]+f[i][j][k-d[p]] 

    d[p]表示第p个循环节的长度

    注意枚举顺序,p要在最外面,保证每个物品只取一次

    置换的循环在不变元素中一定是一个颜色

    嘤嘤。。。。我也没有懂DP啊。如果哪个大佬懂了,一定要给我说一下啊!!!


    啊我懂了,这个dp[i]就代表这个循环的长度,那么我们f[i][j][k]=f[i-d[p]][j][k]+f[i][j-d[p]][k]+f[i][j][k-d[p]] 就代表这个循环分别全部是是红,蓝,绿的数目之和,求到最后的f[sr][sb][sg]就是全部的循环长度为1的个数。

    代码

    #include<iostream>
    #include<stdio.h>
    #include<string.h>
    #include<algorithm>
    #include<map>
    using namespace std;
    int sr,sb,sg,m,p;
    int a[100];//记录置换
    int b[100];//b[i]表示循环长度为i
    int f[30][30][30];//f[i][j][k]在i个红色,j个黄色.k个蓝色
    int vis[100];//记录是否是否在一个类里面
    int n;
    int qpow(int a,int b){
      int ans=1;
      while(b){
        if (b&1)ans=ans*a%p;
        a=a*a%p;
        b/=2;
      }
      return ans%p;
    }
    int dfs(){
      memset(f,0,sizeof(f));
      memset(vis,0,sizeof(vis));
      int tot=0;
      for (int i=1;i<=n;i++){//求循环的个数和阶数
        if (!vis[i]){
            vis[i]=1;
            tot++;
            b[tot]=1;
            int j=i;
            while(!vis[a[j]]){
                j=a[j];
                vis[j]=1;
                b[tot]++;
            }
        }
      }
      f[0][0][0]=1;//求所有循环长度为1的循环的个数 置换的循环在不变元素中一定是一个颜色
      for (int z=1;z<=tot;z++){
         for (int i=sr;i>=0;i--){
            for (int j=sb;j>=0;j--){
                for (int k=sg;k>=0;k--){
                  if (i>=b[z])f[i][j][k]+=f[i-b[z]][j][k];
                  if (j>=b[z])f[i][j][k]+=f[i][j-b[z]][k];
                  if (k>=b[z])f[i][j][k]+=f[i][j][k-b[z]];
                  f[i][j][k]=f[i][j][k]%p;
                }
            }
         }
      }
       return f[sr][sb][sg];
    }
    int main(){
      int ans;
      while(~scanf("%d%d%d%d%d",&sr,&sb,&sg,&m,&p)){
         n=sr+sb+sg;
         ans=0;
         for(int i=1;i<=m;i++){
            for (int j=1;j<=n;j++){
               scanf("%d",&a[j]);
            }
            ans+=dfs();
            ans=ans%p;
         }
        m++;
        for (int i=1;i<=n;i++)a[i]=i;
        ans+=dfs();ans=ans%p;
        ans=ans*qpow(m,p-2)%p;
        printf("%d
    ",ans);
      }
      return 0;
    }

    #include<iostream>#include<stdio.h>#include<string.h>#include<algorithm>#include<map>using namespace std;int sr,sb,sg,m,p;int a[100];//记录置换int b[100];//b[i]表示循环长度为iint f[30][30][30];//f[i][j][k]在i个红色,j个黄色.k个蓝色int vis[100];//记录是否是否在一个类里面int n;int qpow(int a,int b){  int ans=1;  while(b){    if (b&1)ans=ans*a%p;    a=a*a%p;    b/=2;  }  return ans%p;}int dfs(){  memset(f,0,sizeof(f));  memset(vis,0,sizeof(vis));  int tot=0;  for (int i=1;i<=n;i++){//求循环的个数和阶数    if (!vis[i]){        vis[i]=1;        tot++;        b[tot]=1;        int j=i;        while(!vis[a[j]]){            j=a[j];            vis[j]=1;            b[tot]++;        }    }  }  f[0][0][0]=1;//求所有循环长度为1的循环的个数 置换的循环在不变元素中一定是一个颜色  for (int z=1;z<=tot;z++){     for (int i=sr;i>=0;i--){        for (int j=sb;j>=0;j--){            for (int k=sg;k>=0;k--){              if (i>=b[z])f[i][j][k]+=f[i-b[z]][j][k];              if (j>=b[z])f[i][j][k]+=f[i][j-b[z]][k];              if (k>=b[z])f[i][j][k]+=f[i][j][k-b[z]];              f[i][j][k]=f[i][j][k]%p;            }        }     }  }   return f[sr][sb][sg];}int main(){  int ans;  while(~scanf("%d%d%d%d%d",&sr,&sb,&sg,&m,&p)){     n=sr+sb+sg;     ans=0;     for(int i=1;i<=m;i++){        for (int j=1;j<=n;j++){           scanf("%d",&a[j]);        }        ans+=dfs();        ans=ans%p;     }    m++;    for (int i=1;i<=n;i++)a[i]=i;    ans+=dfs();ans=ans%p;    ans=ans*qpow(m,p-2)%p;    printf("%d ",ans);  }  return 0;}

    有不懂欢迎咨询 QQ:1326487164(添加时记得备注)
  • 相关阅读:
    zip加密-字符串加密成字符串
    语言学习第一天
    localStorage和sessionStorage数据存储
    ValueOf()和toString()
    call()与apply()区别typeof和instanceof的区别
    javaScript判断手机型号
    HTML&CSS
    Doctype 严格模式与混杂模式-如何触发这两种模式,区分它们有何意义?
    获得地址栏内的参数
    私有变量
  • 原文地址:https://www.cnblogs.com/bluefly-hrbust/p/9642808.html
Copyright © 2020-2023  润新知