zoukankan      html  css  js  c++  java
  • bzoj 1004

    计数好题

    首先看到这种问题直接想到的应该是polya定理

    可是对颜色使用个数有限制啊!

    没关系,我们分析一下polya定理的表达式:

    $frac{1}{|G|}sum_{i=1}^{n}m^{c_{i}}$

    可以看到,这其中的每一项等价于用$m$种颜色对每个循环节任意染色的方案数(即对每个循环节内的元素染成相同颜色的方案数)

    因此对于这个有限制的问题,我们可以用简单的背包求出这一方案数

    最后对方案数求和,乘个逆元即可

    注意:不要忘了群的基本定义,一个置换群里是需要单位元的,因此需要补充一个原始置换

    代码:

    #include <cstdio>
    #include <cmath>
    #include <cstring>
    #include <cstdlib>
    #include <iostream>
    #include <algorithm>
    #include <queue>
    #include <stack>
    #define ll long long
    using namespace std;
    ll sr,sb,sg,m,p;
    int to[65];
    bool vis[65];
    int siz[65][65];
    ll f[65][25][25][25];
    int val[65];
    ll pow_mul(ll x,ll y)
    {
        ll ret=1;
        while(y)
        {
            if(y&1)ret=ret*x%p;
            x=x*x%p,y>>=1;
        }
        return ret;
    }
    int main()
    {
        scanf("%lld%lld%lld%lld%lld",&sr,&sb,&sg,&m,&p);
        ll n=sr+sb+sg;
        for(int i=1;i<=m;i++)
        {
            for(int j=1;j<=n;j++)scanf("%d",&to[j]);
            memset(vis,0,sizeof(vis));
            for(int j=1;j<=n;j++)
            {
                int p=j;
                if(vis[p])continue;
                val[i]++;
                while(!vis[p])
                {
                    siz[i][val[i]]++;
                    vis[p]=1;
                    p=to[p];
                }
            }
        }    
        m++;
        val[m]=n;
        for(int i=1;i<=n;i++)siz[m][i]=1;
        ll s=0;
        for(int t=1;t<=m;t++)//枚举第几个循环 
        {
            ll S=0;
            memset(f,0,sizeof(f));
            f[0][0][0][0]=1;
            for(int i=1;i<=val[t];i++)
            {
                S+=siz[t][i];
                for(int j=0;j<=sr;j++)//枚举红色的个数 
                {
                    for(int k=0;k<=sb;k++)
                    {
                        if(S-j-k>sg)continue;
                        if(j>=siz[t][i])f[i][j][k][S-j-k]+=f[i-1][j-siz[t][i]][k][S-j-k];
                        if(k>=siz[t][i])f[i][j][k][S-j-k]+=f[i-1][j][k-siz[t][i]][S-j-k];
                        if(S-j-k>=siz[t][i])f[i][j][k][S-j-k]+=f[i-1][j][k][S-j-k-siz[t][i]];
                        f[i][j][k][S-j-k]%=p;                
                    }
                }
            }
            s+=f[val[t]][sr][sb][sg];
            s%=p;
        }
        s=s*pow_mul(m,p-2)%p;
        printf("%lld
    ",s);
        return 0;
    }
  • 相关阅读:
    LeetCode "Super Ugly Number" !
    LeetCode "Count of Smaller Number After Self"
    LeetCode "Binary Tree Vertical Order"
    LeetCode "Sparse Matrix Multiplication"
    LeetCode "Minimum Height Tree" !!
    HackerRank "The Indian Job"
    HackerRank "Poisonous Plants"
    HackerRank "Kundu and Tree" !!
    LeetCode "Best Time to Buy and Sell Stock with Cooldown" !
    HackerRank "AND xor OR"
  • 原文地址:https://www.cnblogs.com/zhangleo/p/11010654.html
Copyright © 2011-2022 走看看