zoukankan      html  css  js  c++  java
  • bzoj 1004 burnside 引理+DP

      对于burnside引理需要枚举染色,这道题属于burnside的一种简单求解的方法,就是polya,我们可以使每一种置换中的循环节中的元素的颜色都相同,那么这样的话就可以直接DP了,我们可以将m个置换单独考虑,处理出当前置换中各个循环节,那么用w[aa][bb][cc]表示在使用了aa个颜色1,bb个颜色2,cc个颜色3时,我们的轨道数,那么我们可以通过背包来累加答案,w[aa][bb][cc]+=w[aa-b[i]][bb][cc] w[aa][bb][cc]+=w[aa][bb-b[i]][cc] w[aa][bb][cc]+=w[aa-b[i]][bb][cc-b[i]]。

      

    /**************************************************************
        Problem: 1004
        User: BLADEVIL
        Language: C++
        Result: Accepted
        Time:84 ms
        Memory:868 kb
    ****************************************************************/
     
    //By BLADEVIL
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #define maxn 70
     
    using namespace std;
     
    int sa,sb,sc,m,n,p,ans;
    int a[maxn],b[maxn],w[25][25][25],flag[maxn];
     
    int mi(int a,int k) { 
        int ans=1;
        while (k) {
            if (k&1) ans=(ans*a)%p;
            a=(a*a)%p;
            k>>=1;
        }
        return ans;
    }
     
    int main() {
        scanf("%d%d%d%d%d",&sa,&sb,&sc,&m,&p); n=sa+sb+sc;
        ans=1;
        for (int i=1;i<=n;i++) ans=(ans*i)%p;
        //printf("%d
    ",ans);
        //printf("|%d
    ",mi(3,3));
        for (int i=1;i<=sa;i++) ans=(ans*mi(i,p-2))%p;
        for (int i=1;i<=sb;i++) ans=(ans*mi(i,p-2))%p;
        for (int i=1;i<=sc;i++) ans=(ans*mi(i,p-2))%p;
        //printf("%d
    ",ans);
        int cur=m;
        while (cur--) {
            for (int i=1;i<=n;i++) scanf("%d",&a[i]);
            memset(flag,0,sizeof flag);
            memset(b,0,sizeof b);
            memset(w,0,sizeof w);
            for (int i=1;i<=n;i++) if (!flag[i]) {
                b[++b[0]]=1; flag[i]=1;
                for (int cur=a[i];cur!=i;cur=a[cur]) b[b[0]]++,flag[cur]=1;
            }
            //for (int i=1;i<=b[0];i++) printf("%d ",b[i]); printf("
    ");
            w[0][0][0]=1;
            for (int i=1;i<=b[0];i++)
                for (int aa=sa;aa;aa--)
                    for (int bb=sb;bb;bb--)
                        for (int cc=sc;cc;cc--) {
                            if (aa>=b[i]) w[aa][bb][cc]=(w[aa][bb][cc]+w[aa-b[i]][bb][cc])%p;
                            if (bb>=b[i]) w[aa][bb][cc]=(w[aa][bb][cc]+w[aa][bb-b[i]][cc])%p;
                            if (cc>=b[i]) w[aa][bb][cc]=(w[aa][bb][cc]+w[aa][bb][cc-b[i]])%p;
                        }
            ans=(ans+w[sa][sb][sc])%p;
            //printf("%d
    ",ans);   
        }
        ans=(ans*mi(m+1,p-2))%p;
        printf("%d
    ",ans);
        return 0;
    }
  • 相关阅读:
    【python】 time模块和datetime模块详解 【转】
    【python 】装饰器 (多个参数的函数,带参数的装饰器)【转】
    从测试角度对测试驱动开发的思考【转】
    mysql性能优化-慢查询分析、优化索引和配置【转】
    【python 】Requests 库学习笔记
    二本院校计算机专业考研上岸985
    mysql创建触发器
    pat 1134 Vertex Cover (25分) 超时问题
    数据库三级封锁协议简述
    pat 1139 First Contact (30分) 题目详解
  • 原文地址:https://www.cnblogs.com/BLADEVIL/p/3622314.html
Copyright © 2011-2022 走看看