其他分享
首页 > 其他分享> > bzoj1004 动态规划/Burnside

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).

标签:方案,动态,int,sr,70,Burnside,include,bzoj1004,mod
来源: https://www.cnblogs.com/Moxingtianxia/p/11366732.html