bzoj 1004: [HNOI2008]Cards
2014-01-05 19:10
253 查看
一道群论题。。要用到Burnside引理
这里copy一下别人写的题解好了。。
介绍一种组合数学中的Pólya计数法、Burnside定理。
群
给定一个集合G={a,b,c,…}和集合G上的二元运算,并满足:
(a) 封闭性:"a,bÎG, $cÎG, a*b=c。
(b) 结合律:"a,b,cÎG, (a*b)*c=a*(b*c)。
(c) 单位元:$eÎG, "aÎG, a*e=e*a=a。
(d) 逆元:"aÎG, $bÎG, a*b=b*a=e,记b=a-1。
则称集合G在运算*之下是一个群,简称G是群。一般a*b简写为ab。
置换
n个元素1,2,…,n之间的一个置换表示1被1到n中的某个数a1取代,2被1到n中的某个数a2取代,直到n被1到n中的某个数an取代,且a1,a2,…,an互不相同。
置换群
置换群的元素是置换,运算是置换的连接。例如:
可以验证置换群满足群的四个条件。
Burnside引理介绍
下面我们介绍Pólya计数法所要用到的一个引理——Burnside定理。
用D(aj) 表示在置换aj下不变的元素的个数。L表示本质不同的方案数。
例题:对N个格子进行2色染色(用X\E各表示一种颜色)。并且格子可以通过m种置换进行变换。求本质不同的染色法。
对于N=4的情况。一共有4个置换:
所有方案在置换a1下都不变,D(a1)=16
XXXX和EEEE在置换a2下不变,D(a2)=2
XXXX和EEEE以及XEXE与EXEX在置换a3下不变,D(a3)=4
XXXX和EEEE在置换a4下不变,D(a4)=2
计算出
那么,本质不同的染色法为6种。
置换群的另一种表示法:
比如: =(1 2 4)(3 5)
可以形象地理解成循环节的含义。1-》2,2-》4,4-》1,就可以表示成(1 2 4)
再对每一个循环节合并成群。
题目分析:
通过了解置换和置换群,这道Cards想必就很容易分析及理解了。可以把(m + 1)种洗牌法看作是元素个数为(m +
1)的置换群,每种洗牌法都是一个置换。现在就是要求本质不同的染色法。这个和Burnside定理的不谋而合。对于一般的Burnside定理的应用,
对每一个置换都可以枚举元素状态再判断是否元素经变换后不变,然后求出D(aj)。但是显然这样耗时不讨好,所以来看置换的另一表示法有没有突破口。每一个置换可以由T个循环节组成,每一个循环节显然要染成一样的颜色,这样才能保证整体上元素经过变换后不变。这样我们通过简单的DP统计即可完成D(aj)的计算了。
但是,问题的不同在于,限制了每种颜色的使用次数。sr、sb、sg的限制促进了我们更深一步的思考。针对每一个置换,状态表示为F[u,I,j,k] . u
表示阶段到了第u个循环节,i、j、k依次表示当前阶段sr、sb、sg各使用了i、j、k次。根据上面的分析,很容易写出DP转移方程。A[u]表示循环节的循环节长度,显然这里循环节具体是什么已经不重要了。
F[u,I,j,k] = F[u-1,i-a[u],j,k] + F[u-1,I,j-a[u],k] + F[u-1,I,j,k-a[u]]
在DP时要不断对p取模。还要注意到一个新的问题,我们最后的答案是要求,每一个置换的F数组的答案之和除以置换的总数。显然不能直接做除法。
对于A / B 对p取模,可以这么做。
A / B mod p = A * C mod p , B * C mod p = 1
这里因为m + 1 很小,所以直接枚举C的值即可。更广泛的使用的话,便要用到扩展欧几里德定理。这里不做阐述。
至此,Cards圆满解决。
View Code
这里copy一下别人写的题解好了。。
介绍一种组合数学中的Pólya计数法、Burnside定理。
群
给定一个集合G={a,b,c,…}和集合G上的二元运算,并满足:
(a) 封闭性:"a,bÎG, $cÎG, a*b=c。
(b) 结合律:"a,b,cÎG, (a*b)*c=a*(b*c)。
(c) 单位元:$eÎG, "aÎG, a*e=e*a=a。
(d) 逆元:"aÎG, $bÎG, a*b=b*a=e,记b=a-1。
则称集合G在运算*之下是一个群,简称G是群。一般a*b简写为ab。
置换
n个元素1,2,…,n之间的一个置换表示1被1到n中的某个数a1取代,2被1到n中的某个数a2取代,直到n被1到n中的某个数an取代,且a1,a2,…,an互不相同。
置换群
置换群的元素是置换,运算是置换的连接。例如:
可以验证置换群满足群的四个条件。
Burnside引理介绍
下面我们介绍Pólya计数法所要用到的一个引理——Burnside定理。
用D(aj) 表示在置换aj下不变的元素的个数。L表示本质不同的方案数。
例题:对N个格子进行2色染色(用X\E各表示一种颜色)。并且格子可以通过m种置换进行变换。求本质不同的染色法。
对于N=4的情况。一共有4个置换:
所有方案在置换a1下都不变,D(a1)=16
XXXX和EEEE在置换a2下不变,D(a2)=2
XXXX和EEEE以及XEXE与EXEX在置换a3下不变,D(a3)=4
XXXX和EEEE在置换a4下不变,D(a4)=2
计算出
那么,本质不同的染色法为6种。
置换群的另一种表示法:
比如: =(1 2 4)(3 5)
可以形象地理解成循环节的含义。1-》2,2-》4,4-》1,就可以表示成(1 2 4)
再对每一个循环节合并成群。
题目分析:
通过了解置换和置换群,这道Cards想必就很容易分析及理解了。可以把(m + 1)种洗牌法看作是元素个数为(m +
1)的置换群,每种洗牌法都是一个置换。现在就是要求本质不同的染色法。这个和Burnside定理的不谋而合。对于一般的Burnside定理的应用,
对每一个置换都可以枚举元素状态再判断是否元素经变换后不变,然后求出D(aj)。但是显然这样耗时不讨好,所以来看置换的另一表示法有没有突破口。每一个置换可以由T个循环节组成,每一个循环节显然要染成一样的颜色,这样才能保证整体上元素经过变换后不变。这样我们通过简单的DP统计即可完成D(aj)的计算了。
但是,问题的不同在于,限制了每种颜色的使用次数。sr、sb、sg的限制促进了我们更深一步的思考。针对每一个置换,状态表示为F[u,I,j,k] . u
表示阶段到了第u个循环节,i、j、k依次表示当前阶段sr、sb、sg各使用了i、j、k次。根据上面的分析,很容易写出DP转移方程。A[u]表示循环节的循环节长度,显然这里循环节具体是什么已经不重要了。
F[u,I,j,k] = F[u-1,i-a[u],j,k] + F[u-1,I,j-a[u],k] + F[u-1,I,j,k-a[u]]
在DP时要不断对p取模。还要注意到一个新的问题,我们最后的答案是要求,每一个置换的F数组的答案之和除以置换的总数。显然不能直接做除法。
对于A / B 对p取模,可以这么做。
A / B mod p = A * C mod p , B * C mod p = 1
这里因为m + 1 很小,所以直接枚举C的值即可。更广泛的使用的话,便要用到扩展欧几里德定理。这里不做阐述。
至此,Cards圆满解决。
/* ID:zsy99021 PROB:bzoj1004 LANG:C++ */ #include <cstdio> #include <cstring> #include <algorithm> #include <cmath> #include <iostream> #include <fstream> #include <ctime> #define N 68 #define M 28 #define mid(l,r) ((l+r) >> 1) #define INF 0x7ffffff using namespace std; int n,m,sr,sb,sg,rep ,ans,f [M][M][M],loop ,tot,reply,p; void init() { bool flag ; for (int i = 1;i <= n;i++) scanf("%d",&rep[i]); memset(loop,0,sizeof(loop)); memset(f,0,sizeof(f)); f[0][0][0][0] = 1; memset(flag,0,sizeof(flag)); tot = 0; reply = 0; for (int i = 1;i <= n;i++) if (!flag[i]) { int r = 1; for (int j = rep[i];j != i;j = rep[j],r++) flag[j] = true; loop[++tot] = r; } } void init1() { bool flag ; for (int i = 1;i <= n;i++) rep[i] = i; memset(loop,0,sizeof(loop)); memset(f,0,sizeof(f)); f[0][0][0][0] = 1; memset(flag,0,sizeof(flag)); tot = 0; reply = 0; for (int i = 1;i <= n;i++) if (!flag[i]) { int r = 1; for (int j = rep[i];j != i;j = rep[j],r++); loop[++tot] = r; } } void col(int x,int a,int b,int c) { if (a >= loop[x]) f[x][a][b][c] += f[x-1][a-loop[x]][b][c]; if (b >= loop[x]) f[x][a][b][c] += f[x-1][a][b-loop[x]][c]; if (c >= loop[x]) f[x][a][b][c] += f[x-1][a][b][c-loop[x]]; if (f[x][a][b][c] >= p) f[x][a][b][c] %= p; } int work() { init(); for (int l = 1;l <= tot;l++) for (int i = 0;i <= sr;i++) for (int j = 0;j <= sb;j++) for (int k = 0;k <= sg;k++) col(l,i,j,k); return f[tot][sr][sb][sg]; } int work1() { init1(); for (int l = 1;l <= tot;l++) for (int i = 0;i <= sr;i++) for (int j = 0;j <= sb;j++) for (int k = 0;k <= sg;k++) col(l,i,j,k); return f[tot][sr][sb][sg]; } int main() { scanf("%d%d%d%d%d",&sr,&sb,&sg,&m,&p); n = sr + sb + sg; for (int i = 1;i <= m;i++) ans += work(); ans += work1(); int c; for (int i = 1;;i++) if ((i * (m + 1)) % p == 1) { c = i; break; } ans = ans * c % p; printf("%d\n",ans); return 0; }
View Code
相关文章推荐
- bzoj1004 [HNOI2008]Cards【Burnside/Polya】
- BZOJ 1004([HNOI2008]Cards-Polya计数+k背包)
- BZOJ 1004: [HNOI2008]Cards( 置换群 + burnside引理 + 背包dp + 乘法逆元 )
- BZOJ1004 [HNOI2008]Cards(置换群+dp)
- [置换群+背包] BZOJ1004: [HNOI2008]Cards
- BZOJ 1004 【HNOI2008】 Cards
- 【BZOJ1004】【HNOI2008】Cards
- BZOJ 1004: [HNOI2008]Cards(群论)
- Burnside引理和Polya定理 & [bzoj 1004] [HNOI2008]Cards:Burnside引理,动态规划
- BZOJ 1004 [HNOI2008]Cards 置换+burnside定理+逆元
- [BZOJ1004][HNOI2008]Cards(Burnside引理+dp)
- [BZOJ1004][HNOI2008]Cards-Burnside引理
- [bzoj1004][HNOI2008][Cards] (置换群+Burnside引理+动态规划)
- BZOJ1004: [HNOI2008]Cards
- BZOJ1004 [HNOI2008]Cards
- BZOJ1004: [HNOI2008]Cards
- 【bzoj 1004】[HNOI2008]Cards(burnside 引理)
- [BZOJ1004][HNOI2008]Cards(Burnside引理+DP)
- [BZOJ1004] [HNOI2008]Cards解题报告(Burnside引理)
- 【BZOJ1004】【HNOI2008】Cards(群论、Burnside引理、背包dp)