zoukankan      html  css  js  c++  java
  • BZOJ1004: [HNOI2008]Cards

    1004: [HNOI2008]Cards

    Time Limit: 10 Sec  Memory Limit: 162 MB
    Submit: 3938  Solved: 2377
    [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

    【题解】

    等价于给定一个置换集F(需要自己加入(1,2,3,4,...,n)),用三种颜色且每种颜色指定个数进行染色的方案数

    使用Burnside定理,求不动点个数

    不难发现,不动点就是循环节为1的循环,求出每个置换f的循环后,在循环上染色,使得每个独立的循环颜色相等,能够独立出来变成循环节为1的循环

    这个可以用多重背包做,不需要任何优化,体积就是原循环节大小,往三个背包(三种颜色)里装,装满的方案数

    做完之后,把所有不动点个数相加,除以置换数m + 1即可

     1 #include <iostream>
     2 #include <cstdio>
     3 #include <cstring>
     4 #include <cstdlib>
     5 #include <algorithm>
     6 #include <queue>
     7 #include <vector>
     8 #include <cmath> 
     9 #define min(a, b) ((a) < (b) ? (a) : (b))
    10 #define max(a, b) ((a) > (b) ? (a) : (b))
    11 #define abs(a) ((a) < 0 ? (-1 * (a)) : (a))
    12 inline void swap(int &a, int &b)
    13 {
    14     long long tmp = a;a = b;b = tmp;
    15 }
    16 inline void read(int &x)
    17 {
    18     x = 0;char ch = getchar(), c = ch;
    19     while(ch < '0' || ch > '9') c = ch, ch = getchar();
    20     while(ch <= '9' && ch >= '0') x = x * 10 + ch - '0', ch = getchar();
    21     if(c == '-') x = -x;
    22 }
    23 
    24 const int INF = 0x3f3f3f3f;
    25 const int MAXN = 60;
    26 
    27 int dp[MAXN + 5][MAXN + 5][MAXN + 5], size[MAXN], tot, s[MAXN], b[MAXN];
    28 int sr,sb,sg,m,p,n,sum;
    29 
    30 int pow(int a, int b)
    31 {
    32     int r = 1, base = a;
    33     for(;b;b >>= 1)
    34     {
    35         if(b & 1) r *= base, r %= p;
    36         base *= base, base %= p;
    37     }
    38     return r;
    39 } 
    40 
    41 int ni(int x)
    42 {
    43     return pow(x, p - 2);
    44 }
    45 
    46 int main()
    47 {
    48     read(sr), read(sb), read(sg), read(m), read(p);
    49     n = sr + sb + sg;
    50     for(register int i = 1;i <= m + 1;++ i)
    51     {            
    52         tot = 0;memset(dp, 0, sizeof(dp));memset(size, 0, sizeof(size));memset(b, 0, sizeof(b));    
    53         if(i == m + 1) for(register int j = 1;j <= n;++ j) s[j] = j;
    54         else for(register int j = 1;j <= n;++ j) read(s[j]);
    55         for(register int j = 1;j <= n;++ j)
    56             if(!b[j])
    57             {
    58                 ++ tot;
    59                 int k = j;
    60                 do
    61                 {
    62                     b[k] = 1;
    63                         ++ size[tot];
    64                     k = s[k];
    65                 }while(k != j);
    66             }
    67         dp[0][0][0] = 1;
    68         for(register int j = 1;j <= tot;++ j)
    69             for(register int r = sr;r >= 0;-- r)
    70                 for(register int b = sb;b >= 0;-- b)
    71                     for(register int g = sg;g >= 0;-- g)
    72                     {
    73                         int &tmp = dp[r][b][g];
    74                         if(g >= size[j]) tmp += dp[r][b][g - size[j]];if(tmp >= p) tmp -= p;
    75                         if(b >= size[j]) tmp += dp[r][b - size[j]][g];if(tmp >= p) tmp -= p;
    76                         if(r >= size[j]) tmp += dp[r - size[j]][b][g];if(tmp >= p) tmp -= p;
    77                     }
    78         sum += dp[sr][sb][sg];
    79         if(sum >= p) sum -= p;
    80     }
    81     printf("%d
    ", sum * ni(m + 1) % p);
    82     return 0;
    83 }
    BZOJ1004
  • 相关阅读:
    如何理解python中的if __name__=='main'的作用
    如何在阿里云上部署war包到tomcat服务器
    如何在windows上部署war包到tomcat服务器
    解决:mysql5.7 timestamp默认值0000-00-00 00:00:00 报错
    python3中的unicode_escape
    python中的excel操作
    python的logging模块
    python中的SMTP发送邮件
    python中的字符串
    一道问题引出的python中可变数据类型与不可变数据类型
  • 原文地址:https://www.cnblogs.com/huibixiaoxing/p/8319003.html
Copyright © 2011-2022 走看看