【BZOJ 1004】 1004: [HNOI2008]Cards (置换、burnside引理)
1004: [HNOI2008]Cards
Description
小春现在很清闲,面对书桌上的N张牌,他决定给每张染色,目前小春只有3种颜色:红色,蓝色,绿色.他询问Sun有
多少种染色方案,Sun很快就给出了答案.进一步,小春要求染出Sr张红色,Sb张蓝色,Sg张绝色.他又询问有多少种方
案,Sun想了一下,又给出了正确答案. 最后小春发明了M种不同的洗牌法,这里他又问Sun有多少种不同的染色方案.
两种染色方法相同当且仅当其中一种可以通过任意的洗牌法(即可以使用多种洗牌法,而每种方法可以使用多次)洗
成另一种.Sun发现这个问题有点难度,决定交给你,答案可能很大,只要求出答案除以P的余数(P为质数).Input
第一行输入 5 个整数:Sr,Sb,Sg,m,p(m<=60,m+1<p<100)。n=Sr+Sb+Sg。
接下来 m 行,每行描述一种洗牌法,每行有 n 个用空格隔开的整数 X1X2...Xn,恰为 1 到 n 的一个排列,
表示使用这种洗牌法,第 i位变为原来的 Xi位的牌。输入数据保证任意多次洗牌都可用这 m种洗牌法中的一种代
替,且对每种洗牌法,都存在一种洗牌法使得能回到原状态。Output
不同染法除以P的余数
Sample Input
1 1 1 2 7
2 3 1
3 1 2Sample Output
2HINT
有2 种本质上不同的染色法RGB 和RBG,使用洗牌法231 一次可得GBR 和BGR,使用洗牌法312 一次 可得BRG
和GRB。
100%数据满足 Max{Sr,Sb,Sg}<=20。
【分析】
这一题是直接输入了m个置换的。
把输入的置换变成互不相交的循环,根据burnside引理我们要求让所有循环节里的元素颜色相同的方案数,但是3种颜色都规定了数量的,所以用三维DP可以求出方案数,最后求均值。
有一个不懂的地方就是,为什么不用计算那m个置换的乘积的贡献呢??【问号??
好吧我没看题。。题目上说保证任意多次洗牌都可用这 m种洗牌法中的一种代替
其他地方还是很好算的。
1 #include<cstdio> 2 #include<cstdlib> 3 #include<cstring> 4 #include<iostream> 5 #include<algorithm> 6 using namespace std; 7 #define Maxn 110 8 9 int a[Maxn],f[25][25][25]; 10 bool vis[Maxn]; 11 int l[Maxn]; 12 int Sr,Sb,Sg,m,p,n; 13 14 void ffind() 15 { 16 memset(f,0,sizeof(f)); 17 f[0][0][0]=1; 18 for(int q=1;q<=l[0];q++) 19 { 20 for(int i=Sr;i>=0;i--) 21 for(int j=Sb;j>=0;j--) 22 for(int k=Sg;k>=0;k--) 23 { 24 if(i>=l[q]) f[i][j][k]=(f[i][j][k]+f[i-l[q]][j][k])%p; 25 if(j>=l[q]) f[i][j][k]=(f[i][j][k]+f[i][j-l[q]][k])%p; 26 if(k>=l[q]) f[i][j][k]=(f[i][j][k]+f[i][j][k-l[q]])%p; 27 } 28 } 29 } 30 31 int qpow(int a,int b) 32 { 33 int ans=1; 34 while(b) 35 { 36 if(b&1) ans=(ans*a)%p; 37 a=(a*a)%p; 38 b>>=1; 39 } 40 return ans; 41 } 42 43 int main() 44 { 45 scanf("%d%d%d%d%d",&Sr,&Sb,&Sg,&m,&p); 46 n=Sr+Sb+Sg; 47 int ans=0; 48 m++; 49 for(int i=1;i<=m;i++) 50 { 51 if(i!=m) 52 { 53 for(int j=1;j<=n;j++) scanf("%d",&a[j]); 54 } 55 else for(int j=1;j<=n;j++) a[j]=j; 56 l[0]=0; 57 for(int j=1;j<=n;j++) vis[j]=0; 58 for(int j=1;j<=n;j++) if(vis[j]==0) 59 { 60 int x=j,cnt=0; 61 while(vis[x]==0) 62 { 63 vis[x]=1; 64 cnt++; 65 x=a[x]; 66 } 67 l[++l[0]]=cnt; 68 } 69 ffind(); 70 ans=(ans+f[Sr][Sb][Sg])%p; 71 } 72 ans=(ans*qpow(m,p-2))%p; 73 printf("%d\n",ans); 74 return 0; 75 }
2017-01-12 15:51:25