zoukankan      html  css  js  c++  java
  • 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
    ",ans*qpow(m+1,p-2)%p); return;
     94 }
     95 
     96 int main(){
     97     File("cards");
     98     work();
     99     return 0;
    100 }
  • 相关阅读:
    设计模式享元模式实现C++
    并查集
    设计模式代理模式实现C++
    设计模式装饰模式实现C++
    最小生成树Prim算法实现
    图的邻接矩阵存储
    威佐夫博弈(Wythoff Game)初识 HDU 1527 POJ 1067
    设计模式原型模式实现C++
    三种经典博弈问题 BashGame;WythoffGame;NimmGame;
    设计模式外观模式实现C++
  • 原文地址:https://www.cnblogs.com/wfj2048/p/6937028.html
Copyright © 2011-2022 走看看