1. 程式人生 > >bzoj1004 [HNOI2008]Cards

bzoj1004 [HNOI2008]Cards

hnoi ans 大小 inpu 藍色 其中 lib 很快 clu

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