bzoj 1004 Cards

来源:互联网 发布:数据库与服务器 编辑:程序博客网 时间:2024/06/03 23:43

1004: [HNOI2008]Cards
Time Limit: 10 Sec Memory Limit: 162 MB
Submit: 3605 Solved: 2155
[Submit][Status][Discuss]
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引理
分别计算每一个置换下的循环节个数,那么循环节各部分相互独立,循环节内部只能染一个颜色= =
啪啪啪一顿背包

现在才学burnside…NOI药丸啊


【代码】

//bzoj 1004 Cards#include<cstdio>#include<cstring>#include<iostream>#include<algorithm>#define ll long long#define fo(i,j,k) for(i=j;i<=k;i++)using namespace std;const int mxn=65;bool vis[mxn];int n,m,p,a,b,c,ans;int A[mxn],f[mxn],sum[mxn],dp[mxn][25][25];inline int ksm(int x,int k){    if(k==0) return 1;    if(k==1) return x%p;    int tmp=ksm(x,k>>1);    if(k&1) return tmp*tmp*x%p;    else return tmp*tmp%p;}inline int dfs(int now,int cnt){    if(vis[now]) return cnt;    vis[now]=1,dfs(A[now],cnt+1);}inline int DP(){    int i,j,k,tot=0;    memset(vis,0,sizeof vis);    memset(dp,0,sizeof dp);    fo(i,1,n)      if(!vis[A[i]])        f[++tot]=dfs(A[i],0);    fo(i,1,tot) sum[i]=sum[i-1]+f[i];    dp[0][0][0]=1;    fo(i,1,tot)      fo(j,0,a)        fo(k,0,b)        {            if(j>=f[i]) dp[i][j][k]+=dp[i-1][j-f[i]][k];            if(k>=f[i]) dp[i][j][k]+=dp[i-1][j][k-f[i]];            if(sum[i]-j-k>=f[i]) dp[i][j][k]+=dp[i-1][j][k];            dp[i][j][k]%=p;        }    return dp[tot][a][b];}int main(){    int i,j,k;    scanf("%d%d%d%d%d",&a,&b,&c,&m,&p);    n=a+b+c;    fo(i,1,m)    {        fo(j,1,n) scanf("%d",&A[j]);        ans=(ans+DP())%p;    }    fo(i,1,n) A[i]=i;    ans=(ans+DP())%p;    printf("%d\n",ans*ksm(m+1,p-2)%p);    return 0;}
原创粉丝点击