zoukankan      html  css  js  c++  java
  • [BZOJ1004] [HNOI2008] Cards (Polya定理)

    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

    Solution

      $Polya$定理($Burnside$引理)戳这

      其作用就是求出有几种本质不同的染色方案

      由于每种颜色的个数有限制,需要用三维的$0/1$背包求出每一种置换下不动点方案数(注意不洗牌也是一种置换)

      呃,需要用乘法逆元,否则你会死得很难看

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 int p, x[65][65], f[25][25][25], siz[65];
     4 bool vis[65];
     5 
     6 int qpow(int a, int b)
     7 {
     8     int ans = 1;
     9     for(; b; b >>= 1, a = a * a % p)
    10         if(b & 1) ans = ans * a % p;
    11     return ans;
    12 }
    13 
    14 int main()
    15 {
    16     int sr, sg, sb, m, inv, ans = 0, tot;
    17     cin >> sr >> sb >> sg >> m >> p;
    18     for(int i = 1; i <= m; ++i)
    19         for(int j = 1; j <= sr + sg + sb; ++j)
    20             cin >> x[i][j];
    21     for(int i = 1; i <= sr + sg + sb; ++i)
    22         x[m + 1][i] = i;
    23     for(int z = 1; z <= m + 1; ++z)
    24     {
    25         memset(f, 0, sizeof(f));
    26         memset(vis, 0, sizeof(vis));
    27         memset(siz, 0, sizeof(siz));
    28         f[0][0][0] = 1, tot = 0;
    29         for(int i = 1; i <= sr + sg + sb; ++i)
    30             if(!vis[i])
    31             {
    32                 ++tot;
    33                 for(int j = i; !vis[j]; j = x[z][j])
    34                     vis[j] = true, ++siz[tot];
    35             }
    36         for(int l = 1; l <= tot; ++l)
    37             for(int i = sr; ~i; --i)
    38                 for(int j = sg; ~j; --j)
    39                     for(int k = sb; ~k; --k)
    40                     {
    41                         if(i >= siz[l])
    42                             f[i][j][k] = (f[i][j][k] + f[i - siz[l]][j][k]) % p;
    43                         if(j >= siz[l])
    44                             f[i][j][k] = (f[i][j][k] + f[i][j - siz[l]][k]) % p;
    45                         if(k >= siz[l])
    46                             f[i][j][k] = (f[i][j][k] + f[i][j][k - siz[l]]) % p;
    47                     }
    48         ans = (ans + f[sr][sg][sb]) % p;
    49     }
    50     cout << ans * qpow(m + 1, p - 2) % p << endl;
    51     return 0;
    52 }
    View Code
  • 相关阅读:
    Jersey Politics
    网络流——最小费用最大流
    网络流——最大流Dinic算法
    【洛谷2756】飞行员配对方案问题(二分图匹配,网络流24题)
    状压dp入门
    2018九江市赛
    [CQOI2007]余数求和
    CSAPC2008 skyline
    [ZJOI2009]函数 题解
    由不定方程想到的——数论选讲
  • 原文地址:https://www.cnblogs.com/CtrlCV/p/5618754.html
Copyright © 2011-2022 走看看