[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的余数

输入输出样例

输入样例#1: 复制
1 1 1 2 7
2 3 1
3 1 2
输出样例#1: 复制
2

说明

有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 }

 

posted @ 2017-10-22 14:51  Z-Y-Y-S  阅读(194)  评论(0编辑  收藏  举报