首页 > 代码库 > bzoj1004 [HNOI2008]Cards

bzoj1004 [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 2

Sample Output

2

HINT

有2 种本质上不同的染色法RGB 和RBG,使用洗牌法231 一次可得GBR 和BGR,使用洗牌法312 一次 可得BRG 和GRB。
100%数据满足 Max{Sr,Sb,Sg}<=20。

 

正解:$polya$定理。

比较水的一道题吧,因为题目直接告诉你要怎么置换了。。

这题与普通的$polya$定理不一样,所以我们肯定不能直接那么搞。容易发现$3$种颜色要正好满足数量限制,可以用三维背包来搞一下。

然后我们对于每种置换,求出每个循环的大小,因为一个循环的颜色是要一样的,那么我们直接把它当成一个有体积的物体,搞一下背包就行了。

注意不要漏掉不置换的情况,最后乘上$m+1$的逆元就行了。

 

  1 //It is made by wfj_2048~  2 #include <algorithm>  3 #include <iostream>  4 #include <complex>  5 #include <cstring>  6 #include <cstdlib>  7 #include <cstdio>  8 #include <vector>  9 #include <cmath> 10 #include <queue> 11 #include <stack> 12 #include <map> 13 #include <set> 14 #define inf (1<<30) 15 #define il inline 16 #define RG register 17 #define ll long long 18 #define File(s) freopen(s".in","r",stdin),freopen(s".out","w",stdout) 19  20 using namespace std; 21  22 int f[65][25][25][25],fa[65],sz[65],s[65],x[65],n,m,M,p,sr,sb,sg,cnt,ans; 23  24 il int gi(){ 25     RG int x=0,q=1; RG char ch=getchar(); 26     while ((ch<0 || ch>9) && ch!=-) ch=getchar(); 27     if (ch==-) q=-1,ch=getchar(); 28     while (ch>=0 && ch<=9) x=x*10+ch-48,ch=getchar(); 29     return q*x; 30 } 31  32 il ll qpow(RG ll a,RG ll b){ 33     RG ll ans=1; 34     while (b){ 35     if (b&1) ans=ans*a%p; 36     a=a*a%p,b>>=1; 37     } 38     return ans; 39 } 40  41 il int find(RG int x){ 42     return fa[x]==x ? x : fa[x]=find(fa[x]); 43 } 44  45 il void work(){ 46     sr=gi(),sb=gi(),sg=gi(),m=gi(),p=gi(),n=sr+sb+sg,M=m; 47     while (M--){ 48     for (RG int i=1;i<=n;++i) fa[i]=i,sz[i]=1; cnt=0; 49     for (RG int i=1,u,v;i<=n;++i){ 50         x[i]=gi(),u=find(i),v=find(x[i]); 51         if (u!=v) fa[u]=v,sz[v]+=sz[u]; 52     } 53     memset(f,0,sizeof(f)),f[0][0][0][0]=1; 54     for (RG int i=1;i<=n;++i) if (find(i)==i) s[++cnt]=sz[i]; 55     for (RG int i=1;i<=cnt;++i) 56         for (RG int a=0;a<=sr;++a) 57         for (RG int b=0;b<=sb;++b) 58             for (RG int c=0;c<=sg;++c){ 59             if (a+s[i]<=sr){ 60                 f[i][a+s[i]][b][c]+=f[i-1][a][b][c]; 61                 if (f[i][a+s[i]][b][c]>=p) f[i][a+s[i]][b][c]-=p; 62             } 63             if (b+s[i]<=sb){ 64                 f[i][a][b+s[i]][c]+=f[i-1][a][b][c]; 65                 if (f[i][a][b+s[i]][c]>=p) f[i][a][b+s[i]][c]-=p; 66             } 67             if (c+s[i]<=sg){ 68                 f[i][a][b][c+s[i]]+=f[i-1][a][b][c]; 69                 if (f[i][a][b][c+s[i]]>=p) f[i][a][b][c+s[i]]-=p; 70             } 71             } 72     ans+=f[cnt][sr][sb][sg]; if (ans>=p) ans-=p; 73     } 74     for (RG int i=1;i<=n;++i) s[i]=1; memset(f,0,sizeof(f)),f[0][0][0][0]=1; 75     for (RG int i=1;i<=n;++i) 76     for (RG int a=0;a<=sr;++a) 77         for (RG int b=0;b<=sb;++b) 78         for (RG int c=0;c<=sg;++c){ 79             if (a+s[i]<=sr){ 80             f[i][a+s[i]][b][c]+=f[i-1][a][b][c]; 81             if (f[i][a+s[i]][b][c]>=p) f[i][a+s[i]][b][c]-=p; 82             } 83             if (b+s[i]<=sb){ 84             f[i][a][b+s[i]][c]+=f[i-1][a][b][c]; 85             if (f[i][a][b+s[i]][c]>=p) f[i][a][b+s[i]][c]-=p; 86             } 87             if (c+s[i]<=sg){ 88             f[i][a][b][c+s[i]]+=f[i-1][a][b][c]; 89             if (f[i][a][b][c+s[i]]>=p) f[i][a][b][c+s[i]]-=p; 90             } 91         } 92     ans+=f[n][sr][sb][sg]; if (ans>=p) ans-=p; 93     printf("%lld\n",ans*qpow(m+1,p-2)%p); return; 94 } 95  96 int main(){ 97     File("cards"); 98     work(); 99     return 0;100 }

 

bzoj1004 [HNOI2008]Cards