看这道题时当时觉得懵逼。。。这玩意完全看不懂啊。。。什么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[];//记录置换
int b[];//b[i]表示循环长度为i
int f[][][];//f[i][j][k]在i个红色,j个黄色.k个蓝色
int vis[];//记录是否是否在一个类里面
int n;
int qpow(int a,int b){
int ans=;
while(b){
if (b&)ans=ans*a%p;
a=a*a%p;
b/=;
}
return ans%p;
}
int dfs(){
memset(f,,sizeof(f));
memset(vis,,sizeof(vis));
int tot=;
for (int i=;i<=n;i++){//求循环的个数和阶数
if (!vis[i]){
vis[i]=;
tot++;
b[tot]=;
int j=i;
while(!vis[a[j]]){
j=a[j];
vis[j]=;
b[tot]++;
}
}
}
f[][][]=;//求所有循环长度为1的循环的个数 置换的循环在不变元素中一定是一个颜色
for (int z=;z<=tot;z++){
for (int i=sr;i>=;i--){
for (int j=sb;j>=;j--){
for (int k=sg;k>=;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=;
for(int i=;i<=m;i++){
for (int j=;j<=n;j++){
scanf("%d",&a[j]);
}
ans+=dfs();
ans=ans%p;
}
m++;
for (int i=;i<=n;i++)a[i]=i;
ans+=dfs();ans=ans%p;
ans=ans*qpow(m,p-)%p;
printf("%d\n",ans);
}
return ;
}

#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\n",ans);  }  return 0;}

埋锅。。。BZOJ1004-置换群+burnside定理+的更多相关文章

  1. BZOJ1004 [HNOI2008]Cards 【burnside定理 + 01背包】

    题目链接 BZOJ1004 题解 burnside定理 在\(m\)个置换下本质不同的染色方案数,等于每种置换下不变的方案数的平均数 记\(L\)为本质不同的染色方案数,\(m\)为置换数,\(f(i ...

  2. 我对Burnside定理的理解

    我想了想,发现可以证明burnside定理. 置换:n个元素1,2,-,n之间的一个置换表示1被1到n中的某个数a1取代,2被1到n中的某个数a2取代,直到n被1到n中的某个数an取代,且a1,a2, ...

  3. poj 2409+2154+2888(Burnside定理)

    三道burnside入门题: Burnside定理主要理解置换群置换后每种不动点的个数,然后n种不动点的染色数总和/n为answer. 对于旋转,旋转i个时不动点为gcd(n,i). 传送门:poj ...

  4. HUST 1569(Burnside定理+容斥+数位dp+矩阵快速幂)

    传送门:Gift 题意:由n(n<=1e9)个珍珠构成的项链,珍珠包含幸运数字(有且仅由4或7组成),取区间[L,R]内的数字,相邻的数字不能相同,且旋转得到的相同的数列为一种,为最终能构成多少 ...

  5. 【Burnside定理】&【Pólya定理】

    Burnside & Pólya (详细内容请参阅<组合数学>或2008年cyx的论文,这里只写一些我学习的时候理解困难的几个点,觉得我SB的请轻鄙视……如果有觉得不科学的地方欢迎 ...

  6. poj2409:Let it Bead(置换群 polya定理)

    题目大意:长度为n的项链,要染m种颜色,可以通过旋转或翻转到达的状态视为同一种,问有多少种染色方案. 学了一波polya定理,发现很好理解啊,其实就是burnside定理的扩展. burnside定理 ...

  7. 置换群 Burnside引理 Pólya定理(Polya)

    置换群 设\(N\)表示组合方案集合.如用两种颜色染四个格子,则\(N=\{\{0,0,0,0\},\{0,0,0,1\},\{0,0,1,0\},...,\{1,1,1,1\}\}\),\(|N|= ...

  8. [bzoj1004][HNOI2008][Cards] (置换群+Burnside引理+动态规划)

    Description 小春现在很清闲,面对书桌上的N张牌,他决定给每张染色,目前小春只有3种颜色:红色,蓝色,绿色.他询问Sun有多少种染色方案,Sun很快就给出了答案.进一步,小春要求染出Sr张红 ...

  9. bzoj1004 [HNOI2008]Cards Burnside定理+背包

    题目传送门 思路:首先是Burnside引理,要先学会这个博客. Burnside引理我们总结一下,就是 每种置换下不动点的数量之和除以置换的总数,得到染色方案的数量.        这道题,显然每种 ...

随机推荐

  1. UGUI Set Anchor And Pivot

    我的环境 Unity 5.3.7p4 在运行时动态的设置UI元素的锚点和中心点. 设置Anchor 修改offsetMax不生效 使用下面这段代码设置Anchor并不会生效,尽管他和你在属性面板看到的 ...

  2. 自动获取svn的版本号

    需求 在做打包时,需要获取本地svn仓库的版本号,如下所示: 下面是我试过的几种做法 SubWCRev 使用SubWCRev.exe(TortoiseSVN自带的小工具),用法简单,但获取到的版本号有 ...

  3. 使用administrator身份启动Vs2017

    日常开发中有些项目工程需要按照Administrator 身份进行启动,我们的操作是在vs2017 上右键,administrator 身份启动. 如下图: 但是这样每次都要右键,移动鼠标进行点击. ...

  4. 【算法】LeetCode算法题-Reverse Integer

    这是悦乐书的第143次更新,第145篇原创 01 看题和准备 今天介绍的是LeetCode算法题中Easy级别的第2题(顺位题号是7),给定32位有符号整数,然后将其反转输出.例如: 输入: 123 ...

  5. Java教程01-基础语法

    目录 1. 基本概念 1.1. 环境变量 Path环境变量的作用->寻找命令 classpath变量的作用->寻找类文件 1.2. JDK里面有什么? 1.3. 什么是JRE? 2. Ja ...

  6. python3内置函数练习

    1. abs() abs() 函数返回数字的绝对值. print(abs(1.5236)) # 1.5236 print(abs(1.0)) # 1.0 2. all() all() 函数用于判断给定 ...

  7. D - Counting Test Gym - 101532D 字符串

    Yousef has a string s that is used to build a magical string w by repeating the string s infinitely ...

  8. 设计模式のFacadePattern(外观模式)----结构模式

    一.产生背景 外观模式(Facade Pattern)隐藏系统的复杂性,并向客户端提供了一个客户端可以访问系统的接口.这种类型的设计模式属于结构型模式,它向现有的系统添加一个接口,来隐藏系统的复杂性. ...

  9. CentOS7.6 linux下yum安装redis以及使用

    一.安装redis 1.检查是否有redis yum 源 1 yum install redis 2.下载fedora的epel仓库 1 yum install epel-release 3.安装re ...

  10. 用PHP打造一个高性能好用的网站

    用PHP打造一个高性能好用的网站 1. 说到高可用的话要提一下redis,用过的都知道redis是一个具备数据库特征的nosql,正好弥补了PHP的瓶颈,个人认为PHP的 瓶颈在于数据库,像Apach ...