bzoj1004 动态规划/Burnside

Posted moxingtianxia

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了bzoj1004 动态规划/Burnside相关的知识,希望对你有一定的参考价值。

技术图片
 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cmath>
 4 #include<string>
 5 #include<cstring>
 6 #include<algorithm>
 7 #include<iomanip>
 8 using namespace std;
 9 namespace Moxing
10     int s1,s2,s3,n,m,mod,ans;
11     int a[70][70],f[70][70][70],d[70];
12     bool b[70];
13     int dp(int x)
14         fill(b+1,b+1+n,0);
15         int sum=0,p;
16         for(int i=1;i<=n;i++)
17             if(b[i]) continue ;
18             d[++sum]=1,p=i,b[p]=1;
19             while(!b[a[x][p]])
20                 d[sum]++,b[a[x][p]]=1;
21                 p=a[x][p];
22              
23         
24         for(int i=s1;i>=0;i--)
25             for(int j=s2;j>=0;j--)
26                 for(int k=s3;k>=0;k--)
27                     f[i][j][k]=0;
28                 
29             
30         
31         f[0][0][0]=1;
32         for(int h=1;h<=sum;h++)
33             for(int i=s1;i>=0;i--)
34                 for(int j=s2;j>=0;j--)
35                     for(int k=s3;k>=0;k--)
36                         if(i>=d[h]) f[i][j][k]=(f[i][j][k]+f[i-d[h]][j][k])%mod;
37                         if(j>=d[h]) f[i][j][k]=(f[i][j][k]+f[i][j-d[h]][k])%mod;
38                         if(k>=d[h]) f[i][j][k]=(f[i][j][k]+f[i][j][k-d[h]])%mod;
39                     
40                 
41             
42         
43         return f[s1][s2][s3];
44     
45     void exgcd(int a,int b,int &x,int &y)
46         if(b==0)
47             x=1,y=0;return ;
48         
49         exgcd(b,a%b,x,y);
50         int t=x;x=y,y=t-a/b*y;
51     
52     struct main
53         main()
54             scanf("%d%d%d%d%d",&s1,&s2,&s3,&m,&mod);
55             n=s1+s2+s3;
56             for(int i=1;i<=m;i++)
57                 for(int j=1;j<=n;j++)
58                     scanf("%d",&a[i][j]);
59                 
60             
61             m++;
62             for(int i=1;i<=n;i++) a[m][i]=i;
63             for(int i=1;i<=m;i++)
64                 ans=(ans+dp(i))%mod;
65              
66             int x,y;
67             exgcd(m,mod,x,y);
68             while(x<=0) x+=mod,y-=m;
69             printf("%d",ans*x%mod);
70             exit(0);
71         
72     UniversalLove; 
73  
74 int main()
75     Moxing::main(); 
76 
View Code

Burnside定理:有m个置换k种颜色,所有本质不同的染色方案数就是每种置换的不变元素的个数的平均数。所谓不变元素就是一种染色方案经过置换变换后和没变化之前一样。

染色时,我们先从n张牌中选sr张染成红色,再从剩下的(n-sr)张中选sb张染成蓝色,剩下的染成绿色,根据乘法原理,总方案数为t=C(n,sr)*C(n-sr,sb)*C(n-sr-sb,sg)=C(n,sr)*C(n-sr,sb)*1
在总方案数中,会有一些重复的需要筛去,接下来我们就需要计算所有染色方案中被重复计算了多少次。
共有m种洗牌法,任何一种染色方案(A)都可以根据洗牌法变成其它m种方案。我们把这m+1种方案看作一组,这一组中的方案通过洗牌能且只能变成其它m种方案,且不会有不属于这一组的方案能通过洗牌变成这一组方案的任何一种,固染色方案被我们重复计算了(m+1)次。
ans=(t/(m+1))%p;
最后一步,对于带除法的模运算,我们需要乘(m+1)的逆元。
因为p>m+1且p是质数(题目),所以gcd(m+1,p)=1;由费马小定理可得(m+1)^(p-1)≡1 mod p  —>  (m+1)^(p-2) * (m+1)≡1 mod p
所以(m+1)的逆元为(m+1)^(p-2).

以上是关于bzoj1004 动态规划/Burnside的主要内容,如果未能解决你的问题,请参考以下文章

BZOJ1004Cards(组合数学,Burnside引理)

BZOJ1004 [HNOI2008]Cards burnside定理 + 01背包

bzoj1004: [HNOI2008]Cards(burnside引理+DP)

BZOJ1004[HNOI2008]Cards Burnside引理

bzoj1004[HNOI2008]Cards Burnside引理+背包dp

[BZOJ 1004][HNOI2008]Cards(Polya定理/Burnside引理)