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

    CardsCards


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

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

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

    输入数据保证任意多次洗牌都可用这 m种洗牌法中的一种代替, 且对每种洗牌法, 都存在一种洗牌法使得能回到原状态 .


    Solutionmathcal{Solution}

    加粗字体保证了多次洗牌与使用一次其中一种洗牌方式的结果相同,
    相当于给出的置换总数仍是 MM
    .

    对于MM置换, 根据 BurnsideBurnside引理,
    我们只需将 MM 个置换下 状态始终不变的方案数 numinum_i 叠加,
    再加上 题目没有给出的 单位置换 的方案数, 除 M+1M+1 即可得到答案.


    numinum_i 可以使用 dpdp 求解,
    在第 ii 个置换下, 含有sizesize个循环节, 每个循环节长度为 lenilen_i,

    每个循环节内都必须染上同一个颜色才可以循环.
    要求解的就是 三个不同的背包中 装 sizesize 个物品 .

    F[i,j,k]F[i,j,k] 表示三种颜色分别使用 i,j,ki,j,k 个的方案数,
    F[i,j,k]=F[ileni,j,k]+F[i,jleni,k]+F[i,j,kleni]F[i,j,k]=F[i-len_i,j,k]+F[i,j-len_i,k]+F[i,j,k-len_i],
    最后 F[Sr,Sb,Sg]F[Sr,Sb,Sg] 即为该置换方案数.


    Codemathcal{Code}

    #include<cstdio>
    #include<cstring>
    #define reg register
    
    int Sr;
    int Sb;
    int Sg;
    int M;
    int N;
    int P;
    int mod;
    int Ans;
    int Len[75];
    int len[75];
    int Zh[75][75];
    int F[75][75][75];
    
    bool Used[75];
    
    int gcd(int a, int b){ return !b?a:gcd(b, a%b); }
    
    int Find_circle(int x){
            memset(Used, 0, sizeof Used);
            int s = 0;
            for(reg int i = 1; i <= N; i ++)
                    if(!Used[i]){
                            Used[i] = 1;
                            len[++ s] = 1;
                            int to = Zh[x][i];
                            while(!Used[to]) Used[to] = 1, to = Zh[x][to], len[s] ++;
                    }
            return s;
    }
    
    void Work(int size){
            memset(F, 0, sizeof F);
            F[0][0][0] = 1;
            for(reg int p = 1; p <= size; p ++)
                    for(reg int i = Sr; ~i; i --)
                            for(reg int j = Sb; ~j; j --)
                                    for(reg int k = Sg; ~k; k --){
                                            int &t = F[i][j][k];
                                            if(i >= len[p]) t = (1ll*t + F[i-len[p]][j][k]) % mod;
                                            if(j >= len[p]) t = (1ll*t + F[i][j-len[p]][k]) % mod;
                                            if(k >= len[p]) t = (1ll*t + F[i][j][k-len[p]]) % mod;
                                    }
            Ans = (1ll*Ans + F[Sr][Sb][Sg]);
    }
    
    int KSM(int a, int b){
            a %= mod;
            int s = 1;
            while(b){
                    if(b & 1) s = 1ll*s*a % mod;
                    a = 1ll*a*a % mod;
                    b >>= 1;
            }
            return s;
    }
    
    int main(){
            scanf("%d%d%d%d%d", &Sr, &Sb, &Sg, &M, &P);
            mod = P;
            N = Sr + Sb + Sg;
            for(reg int i = 1; i <= M; i ++)
                    for(reg int j = 1; j <= N; j ++) scanf("%d", &Zh[i][j]);
            for(reg int i = 1; i <= M; i ++) Work(Find_circle(i));
            for(reg int i = 1; i <= N; i ++) len[i] = 1;
            Work(N);
            Ans = (1ll*Ans*KSM(M+1, mod-2)) % mod;
            printf("%d
    ", Ans);
            return 0;
    }
    
    
    
  • 相关阅读:
    python+selenium初学者常见问题处理
    pycharm的这些配置,你都知道吗
    巧用浏览器F12调试器定位系统前后端bug
    dsu + lca
    indeed2017校招在线编程题(网测)三
    rolling hash
    ac自动机
    indeed 第二次笔试题
    vmware以及schlumberger题解
    2017 google Round C APAC Test 题解
  • 原文地址:https://www.cnblogs.com/zbr162/p/11822586.html
Copyright © 2011-2022 走看看