zoukankan      html  css  js  c++  java
  • 【HNOI2008】Cards BZOJ 1004

    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计数法。

         那么就是有这么多给你的置换方法,求本质上不同的排列有多少。我们将每一个置换群分解,找出置换的循环节:

         比如置换1 4 3 5 2可以分解为(1)(2 4 5)(3)这三个循环节。

         由polya计数法得:ans=所有置换中本质相同的方案的平均数。

         看到100%数据满足 Max{Sr,Sb,Sg}<=20可以用dp做。

         用f[i][j][k]表示用了i个红色,j个绿色,k个蓝色的方案数,则f[i][j][k]=f[i-size][j][k]+f[i][j-size][k]+f[i][j][k-size](size是当前循环节的大小)

         最后不要忘记加上(1 2 3 ....n)这个循环,这个可以直接算出有N!/(sr!*sg!*sb!)

         然后除以m+1,p为质数,用逆元算。

     1 #include <iostream>
     2 #include <cstring>
     3 #include <string>
     4 #include <cstdio>
     5 #include <cstdlib>
     6 #include <cmath>
     7 #include <algorithm>
     8 #include <queue>
     9 #include <stack>
    10 #include <map>
    11 #include <set>
    12 #include <list>
    13 #include <vector>
    14 #include <ctime>
    15 #include <functional>
    16 #define pritnf printf
    17 #define scafn scanf
    18 #define For(i,j,k) for(int i=(j);i<=(k);(i)++)
    19 #define Clear(a) memset(a,0,sizeof(a))
    20 using namespace std;
    21 typedef long long LL;
    22 typedef unsigned int Uint; 
    23 const int INF=0x7fffffff;
    24 //==============struct declaration==============
    25 
    26 //==============var declaration=================
    27 const int MAXN=30;
    28 int sr,sb,sg,n,m,p,MOD,cnt=0;
    29 int ans=0;
    30 int tran[MAXN*5];
    31 int f[MAXN][MAXN][MAXN];
    32 bool vis[MAXN*5];
    33 //==============function declaration============
    34 int quickpow(int a,int Exp);
    35 int inv(int a){return quickpow(a,MOD-2);}
    36 int fact(int x){int ans=1;for(int i=1;i<=x;i++) ans=(ans*i)%MOD;return ans;}
    37 //==============main code=======================
    38 int main()
    39 {  
    40 //#define FILE__
    41 #ifdef FILE__
    42   freopen("input.txt","r",stdin);
    43   freopen("output.txt","w",stdout);
    44 #endif  
    45   scanf("%d%d%d%d%d",&sr,&sb,&sg,&m,&MOD);n=sr+sb+sg;
    46   for(int i=1;i<=m;i++){
    47     for(int j=1;j<=n;j++)
    48       scanf("%d",tran+j);
    49     memset(vis,false,sizeof(vis));memset(f,0,sizeof(f));
    50     f[0][0][0]=1;cnt=0;
    51     for(int p=1;p<=n;p++){
    52       if (vis[p]) continue;
    53       cnt++;
    54       int siz=0,x=p;
    55       while (!vis[x]){
    56         vis[x]=true;
    57         x=tran[x];
    58         siz++;
    59       }//找出循环节
    60       for(int i=sr;i>=0;i--)
    61         for(int j=sb;j>=0;j--)
    62           for(int k=sg;k>=0;k--){
    63             if (i>=siz) f[i][j][k]+=f[i-siz][j][k];
    64             if (j>=siz) f[i][j][k]+=f[i][j-siz][k];
    65             if (k>=siz) f[i][j][k]+-f[i][j][k-siz];
    66             f[i][j][k]%=MOD;
    67           } //DP
    68     }
    69     ans=(ans+f[sr][sb][sg])%MOD;
    70   }
    71   ans=ans+fact(n)*inv(fact(sr))*inv(fact(sb))*inv(fact(sg));
    72   printf("%d
    ",(ans*inv(m+1))%MOD);
    73   return 0;
    74 }
    75 //================fuction code====================
    76 int quickpow(int a,int Exp){
    77   if (Exp==0) return 1;
    78   if (Exp==1) return a;
    79   int temp=quickpow(a,Exp/2);
    80   temp=(temp*temp)%MOD;
    81   if (Exp&1) temp=(temp*a)%MOD;
    82   return temp;
    83 }
    Code
  • 相关阅读:
    【转】最大子序列和(动态规划学习)
    [转]修改Oracle XDB的8080端口
    【转】 C++常见编译/链接错误及其解决办法
    Pentaho Dashboard Editor使用向导
    [转]什么是Unicode是什么是UTF8是什么
    【转】 typedef的四个用途和两个陷阱
    【转】 C++中类型转换的解释
    从一道笔试题谈算法优化
    [转]谈谈Unicode编码,简要解释UCS、UTF、BMP、BOM等名词
    [转]对Oracle数据库的字符集问题的资料收集,受益匪浅
  • 原文地址:https://www.cnblogs.com/Houjikan/p/4217193.html
Copyright © 2011-2022 走看看