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

    题目描述

    小春现在很清闲,面对书桌上的N张牌,他决定给每张染色,目前小春只有3种颜色:红色,蓝色,绿色.他询问Sun有多少种染色方案,Sun很快就给出了答案.

    进一步,小春要求染出Sr张红色,Sb张蓝色,Sg张绿色.他又询问有多少种方案,Sun想了一下,又给出了正确答案. 最后小春发明了M种不同的洗牌法,这里他又问Sun有多少种不同的染色方案.两种染色方法相同当且仅当其中一种可以通过任意的洗牌法(即可以使用多种洗牌法,而每种方法可以使用多次)洗成另一种.

    Sun发现这个问题有点难度,决定交给你,答案可能很大,只要求出答案除以P的余数(P为质数).

    输入输出格式

    输入格式:

    第一行输入 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种洗牌法中的一种代替,且对每种

    洗牌法,都存在一种洗牌法使得能回到原状态。

    100%数据满足 Max{Sr,Sb,Sg}<=20。

    输出格式:

    不同染法除以P的余数

    输入输出样例

    输入样例#1: 复制
    1 1 1 2 7
    2 3 1
    3 1 2
    
    输出样例#1: 复制
    2
    

    说明

    有2 种本质上不同的染色法RGB 和RBG,使用洗牌法231 一次可得GBR 和BGR,使用洗牌法312 一次 可得BRG 和GRB。

    分析:

    先学习下几个引理

    burnside引理

    http://blog.csdn.net/liangzhaoyang1/article/details/72639208

    逆元

    https://www.cnblogs.com/linyujun/p/5194184.html

     参考了大神博客

    http://tgotp.science/

    思路:套用burnside引理,这题因为对颜色有限制 不能用 polya ,用动归求出对于一个置换的不动方案数 ;

    dp的一些解释:dp[i][j][k]表示前i个循环, 用了1号颜色j个 2号颜色k个的方案数

    num[n]表示该洗牌法下的循环节个数;

    最后根据burnside引理:

    不同的方案数:I=(C(a1)+C(a2)+...C(ag))/G

    这题的情况是需要除以m

    但是过程中我们都进行的%p

    且(a  /  b) % p = (a%p  /  b%p) %p  是错误的,所以我们要用到逆元(这题因为p是质数,用费马小定理就行)

    (a  /  b) % p = (a * inv(b) ) % p = (a % p * inv(b) % p) % p

    费马小定理

    a^(p-1) ≡1 (mod p)

    所以 inv(a) = a^(p-2) (mod p)

    // 去吧!皮卡丘! 把AC带回来!
    //      へ     /|
    //   /\7    ∠_/
    //   / │   / /
    //  │ Z _,< /   /`ヽ
    //  │     ヽ   /  〉
    //  Y     `  /  /
    //  イ● 、 ●  ⊂⊃〈  /
    //  ()  へ    | \〈
    //   >ー 、_  ィ  │ //
    //   / へ   / ノ<| \\
    //   ヽ_ノ  (_/  │//
    //    7       |/
    //    >―r ̄ ̄`ー―_
    //**************************************
    #pragma comment(linker, "/STACK:1024000000,1024000000")
    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    #define inf 2147483647
    const ll INF = 0x3f3f3f3f3f3f3f3fll;
    #define ri register int
    template <class T> inline T min(T a, T b, T c) { return min(min(a, b), c); }
    template <class T> inline T max(T a, T b, T c) { return max(max(a, b), c); }
    template <class T> inline T min(T a, T b, T c, T d) {
      return min(min(a, b), min(c, d));
    }
    template <class T> inline T max(T a, T b, T c, T d) {
      return max(max(a, b), max(c, d));
    }
    #define scanf1(x) scanf("%d", &x)
    #define scanf2(x, y) scanf("%d%d", &x, &y)
    #define scanf3(x, y, z) scanf("%d%d%d", &x, &y, &z)
    #define scanf4(x, y, z, X) scanf("%d%d%d%d", &x, &y, &z, &X)
    #define pi acos(-1)
    #define me(x, y) memset(x, y, sizeof(x));
    #define For(i, a, b) for (int i = a; i <= b; i++)
    #define FFor(i, a, b) for (int i = a; i >= b; i--)
    #define bug printf("***********
    ");
    #define mp make_pair
    #define pb push_back
    const int maxn = 3e5 + 10;
    const int maxx = 1e6 + 10;
    // name*******************************
    int dp[80][30][30];
    int a[80];
    bool flag[80];
    int num[80];
    int s1, s2, s3, m, mod;
    int tot;
    int ans = 0;
    int sum[80];
    // function******************************
    inline ll qmul(ll a, ll b) {
      ll base = a, ans = 1;
      while (b) {
        if (b & 1ll)
          ans = (ans * base) % mod;
        base = (base * base) % mod;
        b >>= 1ll;
      }
      return ans;
    }
    //***************************************
    int main() {
      // ios::sync_with_stdio(0); cin.tie(0);
      // freopen("test.txt", "r", stdin);
      //  freopen("outout.txt","w",stdout);
      cin >> s1 >> s2 >> s3 >> m >> mod;
      m++;
      tot = s1 + s2 + s3;
      For(t, 1, m) {
        if (t == m)
          For(i, 1, tot) a[i] = i;
        else
          For(i, 1, tot) cin >> a[i];
        memset(flag, 0, sizeof(flag));
        memset(num, 0, sizeof(num));
        memset(sum, 0, sizeof(sum));
        int n = 0;
        For(j, 1, tot) {
          if (!flag[j]) {
            int cnt = 0;
            int p = j;
            while (!flag[p]) {
              flag[p] = 1;
              cnt++;
              p = a[p];
            }
            num[++n] = cnt;
            sum[n] = sum[n - 1] + cnt;
          }
        }
        dp[0][0][0] = 1;
        For(i, 1, n) {
          For(j, 0, s1) {
            For(k, 0, s2) {
              int l = sum[i] - j - k; //?
              if (l < 0 || l > s3)
                continue;
              int sum = 0;
              if (j >= num[i])
                sum = (sum + dp[i - 1][j - num[i]][k]) % mod;
              if (k >= num[i])
                sum = (sum + dp[i - 1][j][k - num[i]]) % mod;
              if (l >= num[i])
                sum = (sum + dp[i - 1][j][k]) % mod;
              dp[i][j][k] = sum;
              if (i == n)
                ans = (ans + dp[i][j][k]) % mod;
            }
          }
        }
      }
      int x = ans * qmul(m, mod - 2) % mod;
      cout << x;
      return 0;
    }
  • 相关阅读:
    Luogu 1080 【NOIP2012】国王游戏 (贪心,高精度)
    Luogu 1314 【NOIP2011】聪明的质检员 (二分)
    Luogu 1315 【NOIP2011】观光公交 (贪心)
    Luogu 1312 【NOIP2011】玛雅游戏 (搜索)
    Luogu 1525 【NOIP2010】关押罪犯 (贪心,并查集)
    Luogu 1514 引水入城 (搜索,动态规划)
    UVA 1394 And Then There Was One / Gym 101415A And Then There Was One / UVAlive 3882 And Then There Was One / POJ 3517 And Then There Was One / Aizu 1275 And Then There Was One (动态规划,思维题)
    Luogu 1437 [HNOI2004]敲砖块 (动态规划)
    Luogu 1941 【NOIP2014】飞扬的小鸟 (动态规划)
    HDU 1176 免费馅饼 (动态规划)
  • 原文地址:https://www.cnblogs.com/planche/p/8493655.html
Copyright © 2011-2022 走看看