[HNOI2008]Cards
题目描述
小春现在很清闲,面对书桌上的N张牌,他决定给每张染色,目前小春只有3种颜色:红色,蓝色,绿色.他询问Sun有多少种染色方案,Sun很快就给出了答案.
进一步,小春要求染出Sr张红色,Sb张蓝色,Sg张绿色.他又询问有多少种方案,Sun想了一下,又给出了正确答案. 最后小春发明了M种不同的洗牌法,这里他又问Sun有多少种不同的染色方案.两种染色方法相同当且仅当其中一种可以通过任意的洗牌法(即可以使用多种洗牌法,而每种方法可以使用多次)洗成另一种.
Sun发现这个问题有点难度,决定交给你,答案可能很大,只要求出答案除以P的余数(P为质数).
输入输出格式
输入格式:
第一行输入 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种洗牌法中的一种代替,且对每种
洗牌法,都存在一种洗牌法使得能回到原状态。
100%数据满足 Max{Sr,Sb,Sg}<=20。
输出格式:
不同染法除以P的余数
输入输出样例
说明
有2 种本质上不同的染色法RGB 和RBG,使用洗牌法231 一次可得GBR 和BGR,使用洗牌法312 一次 可得BRG 和GRB。
题目大意:给出n张牌,分别染a张红色,b张蓝色,c张绿色(n=a+b+c),给出m个置换,问不同的染色方案。
红色部分就是告述你这些置换构成置换群
置换群中的染色方案问题可用polya定理解决。
只要满足同一循环染同一种色
因为3种颜色要满足数量限制,不能用polya,但可以用burnside
所以用三维背包求出在置换$a_j$下不变的元素个数$D(a_j)$
还要算上不置换,也就是单位置换
所以总共有$|G|=m+1$种置换,根据burnside引理
$ans=\frac{1}{G}\sum_{j=1}^{m+1}D(a_j)$
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #include<cmath> 6 using namespace std; 7 int sr,sb,sg,n,m,p,inv; 8 int vis[1001],f[101][21][21][21],tot,A[1001],s[1001],ans; 9 int qpow(int x,int y) 10 { 11 int res=1; 12 while (y) 13 { 14 if (y&1) res=res*x%p; 15 x=x*x%p; 16 y/=2; 17 } 18 return res; 19 } 20 int dfs(int x,int cnt) 21 { 22 if (vis[x]) 23 return cnt; 24 vis[x]=1; 25 return dfs(A[x],cnt+1); 26 } 27 int main() 28 {int i,a,b,c; 29 cin>>sr>>sb>>sg>>m>>p; 30 n=sr+sb+sg; 31 inv=qpow(m+1,p-2); 32 while (m--) 33 { 34 tot=0; 35 memset(vis,0,sizeof(vis)); 36 for (i=1;i<=n;i++) 37 scanf("%d",&A[i]); 38 for (i=1;i<=n;i++) 39 if (vis[i]==0) 40 { 41 s[++tot]=dfs(i,0); 42 } 43 memset(f,0,sizeof(f)); 44 f[0][0][0][0]=1; 45 for (i=1;i<=tot;i++) 46 { 47 for (a=0;a<=sr;a++) 48 { 49 for (b=0;b<=sb;b++) 50 { 51 for (c=0;c<=sg;c++) 52 { 53 if (a>=s[i]) 54 { 55 f[i][a][b][c]+=f[i-1][a-s[i]][b][c]; 56 if (f[i][a][b][c]>=p) f[i][a][b][c]-=p; 57 } 58 if (b>=s[i]) 59 { 60 f[i][a][b][c]+=f[i-1][a][b-s[i]][c],f[i][a][b][c]%=p; 61 if (f[i][a][b][c]>=p) f[i][a][b][c]-=p; 62 } 63 if (c>=s[i]) 64 { 65 f[i][a][b][c]+=f[i-1][a][b][c-s[i]]; 66 if (f[i][a][b][c]>=p) f[i][a][b][c]-=p; 67 } 68 } 69 } 70 } 71 } 72 ans+=f[tot][sr][sb][sg]; 73 if (ans>=p) ans-=p; 74 } 75 memset(f,0,sizeof(f));f[0][0][0][0]=1; 76 for (i=1;i<=n;i++) 77 { 78 for (a=0;a<=sr;a++) 79 { 80 for (b=0;b<=sb;b++) 81 { 82 for (c=0;c<=sg;c++) 83 { 84 if (a>=1) 85 { 86 f[i][a][b][c]+=f[i-1][a-1][b][c]; 87 if (f[i][a][b][c]>=p) f[i][a][b][c]-=p; 88 } 89 if (b>=1) 90 { 91 f[i][a][b][c]+=f[i-1][a][b-1][c],f[i][a][b][c]%=p; 92 if (f[i][a][b][c]>=p) f[i][a][b][c]-=p; 93 } 94 if (c>=1) 95 { 96 f[i][a][b][c]+=f[i-1][a][b][c-1]; 97 if (f[i][a][b][c]>=p) f[i][a][b][c]-=p; 98 } 99 } 100 } 101 } 102 } 103 ans+=f[n][sr][sb][sg]; 104 if (ans>=p) ans-=p; 105 cout<<ans*inv%p; 106 }