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

     小春现在很清闲,面对书桌上的N张牌,他决定给每张染色,目前小春只有3种颜色:红色,蓝色,绿色.他询问Sun有
    多少种染色方案,Sun很快就给出了答案.进一步,小春要求染出Sr张红色,Sb张蓝色,Sg张绝色.他又询问有多少种方
    案,Sun想了一下,又给出了正确答案. 最后小春发明了M种不同的洗牌法,这里他又问Sun有多少种不同的染色方案.
    两种染色方法相同当且仅当其中一种可以通过任意的洗牌法(即可以使用多种洗牌法,而每种方法可以使用多次)洗
    成另一种.Sun发现这个问题有点难度,决定交给你,答案可能很大,只要求出答案除以P的余数(P为质数).

    哇原来burnside引理这么好玩的!棒!赶紧来切道题目~

    我们知道Answer=Σf(i,r,b,g)/(m+1) 其中f(i,r,g,b)表示在第i组置换的不动点个数

    那我们需要用dp来解决一下这个问题:

    f[i-c[x]][j][k]+f[i][j-c[x]][k]+f[i][j][k-c[x]]->f[i][j][k]

    c[x]表示当前置换中第i个循环的长度,显然每个循环的颜色必须相同

    复杂度O(RGBM(R+G+B))


    #include<stdio.h>
    #include<string.h>
    #include<algorithm>
    using namespace std;
    int R,B,G,n,m,P,s[110],w[110],f[21][21][21],ans=0;
    inline int pow(int x,int k,int& s){
        for(;k;x=x*x%P,k>>=1) k&1?s=s*x%P:0;
    }
    int cal(){
        int t=0;
        for(int i=1;i<=n;++i) if(s[i]){
            ++t;
            for(int j=i,k;s[j];j=s[j],s[k]=0) k=j,++w[t];
        }
        memset(f,0,sizeof f); ***f=1;
        for(;t;--t)
            for(int i=R;~i;--i)
                for(int j=G;~j;--j)
                    for(int k=B;~k;--k)
                        f[i][j][k]=((i>=w[t]?f[i-w[t]][j][k]:0)+(j>=w[t]?f[i][j-w[t]][k]:0)+(k>=w[t]?f[i][j][k-w[t]]:0))%P;
        return f[R][G][B];
    }
    int main(){
        scanf("%d%d%d%d%d",&R,&G,&B,&m,&P); n=G+B+R;
        for(int j=1;j<=n;++j) s[j]=j; ans=cal();
        for(int i=1;i<=m;++i){
            for(int j=1;j<=n;++j) scanf("%d",s+i);
            ans=(ans+cal())%P;
        }
        pow(m+1,P-2,ans);
        printf("%d
    ",ans);
    }


  • 相关阅读:
    C++ 重载运算符简单举例
    Python 的几种推导式
    Linux 系统目录结构
    Shell 文件包含
    Shell 文件测试运算符
    Shell 函数定义与调用
    Shell 数组定义与获取
    C 语言精髓之变参函数
    Vim 字符串替换命令
    S5PV210 串口实验(中断方式)
  • 原文地址:https://www.cnblogs.com/Extended-Ash/p/9477137.html
Copyright © 2011-2022 走看看