Bzoj1004 [HNOI2008]Cards

Time Limit: 10 Sec  Memory Limit: 162 MB
Submit: 3449  Solved: 2067

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。

 

Source

数学问题 置换群 burnside引理 动规 背包DP

对于每一种洗牌方式(置换),显然同一个循环节内(即通过该种洗牌方式)只能填同一个颜色。枚举每种置换,统计出其中的循环节大小和尺寸,01背包DP出方案即可。

 

 1 /*by SilverN*/
 2 #include<algorithm>
 3 #include<iostream>
 4 #include<cstring>
 5 #include<cstdio>
 6 #include<cmath>
 7 #include<vector>
 8 #define LL long long
 9 using namespace std;
10 const int mxn=105;;
11 int read(){
12     int x=0,f=1;char ch=getchar();
13     while(ch<'0' || ch>'9'){if(ch=='-')f=-1;ch=getchar();}
14     while(ch>='0' && ch<='9'){x=x*10+ch-'0';ch=getchar();}
15     return x*f;
16 }
17 int sr,sb,sg;
18 int n,m,p;
19 LL f[mxn][mxn][mxn];
20 int a[mxn][mxn];
21 int sz[mxn],cnt=0;
22 bool vis[mxn];
23 LL dp(int x){
24 //  printf("dpx:%d\n",x);
25     int i,j,k,l;
26     memset(vis,0,sizeof vis);
27     cnt=0;
28     for(i=1;i<=n;i++){
29         if(vis[i])continue;
30         vis[i]=1;
31         ++cnt;
32         sz[cnt]=1;
33         int t=a[x][i];
34         while(t!=i){
35             sz[cnt]++;
36             vis[t]=1;
37             t=a[x][t];
38         }
39     }
40     memset(f,0,sizeof f);
41     f[0][0][0]=1;
42     for(i=1;i<=cnt;i++){
43 //      printf("sz:%d\n",sz[i]);
44         for(j=sr;j>=0;j--)
45             for(k=sb;k>=0;k--)
46                 for(l=sg;l>=0;l--){
47                     if(j>=sz[i])f[j][k][l]=(f[j][k][l]+f[j-sz[i]][k][l])%p;
48                     if(k>=sz[i])f[j][k][l]=(f[j][k][l]+f[j][k-sz[i]][l])%p;
49                     if(l>=sz[i])f[j][k][l]=(f[j][k][l]+f[j][k][l-sz[i]])%p;
50                 }
51     }
52 //  printf("res%d:%lld\n",x,f[sr][sb][sg]);
53     return f[sr][sb][sg];
54 }
55 LL ans=0;
56 LL ksm(LL a,LL k){
57     LL res=1;
58     while(k){
59         if(k&1)res=res*a%p;
60         a=a*a%p;
61         k>>=1;
62     }
63     return res;
64 }
65 int main(){
66     int i,j;
67     sr=read();sb=read();sg=read();m=read();p=read();
68     n=sr+sb+sg;
69     for(i=1;i<=m;i++)
70         for(j=1;j<=n;j++)
71             a[i][j]=read();
72     m++;
73     for(i=1;i<=n;i++)a[m][i]=i;
74     LL inv=ksm(m,p-2);
75     for(i=1;i<=m;i++)
76         ans=ans+dp(i);
77 //  printf("ans:%lld inv:%lld\n",ans,inv);
78     ans=ans*inv%p;
79     printf("%lld\n",ans);
80     return 0;
81 }
82 

 

posted @ 2017-04-12 09:18  SilverNebula  阅读(158)  评论(0编辑  收藏  举报
AmazingCounters.com