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

    终于是把这题过了。

    首先,一个赤裸裸的置换在那,显然不是Burnside就是Pólya。

    这题由于有三种颜色且颜色数是有限的,Pólya是没法用了,上Burnside。

    Burnside是说,真正意义上不变的染色方案数=Σ(每种置换下不变的染色方案数)/(置换总数)

    求出每种置换下不变的染色方案数便显得很重要,这里便需要特殊到这道题了。

    对于每一种置换,我们求出其循环节(超像Pólya!),显然的,每个循环节必须染同样的颜色。

    接下来,就能够通过一个DP将整个分子求出。

    而分母,由于是除法,所以需要用到乘法逆元,又因为这里保证p为素数,所以可以直接用快速幂来求逆元。

    调试小结:

      1.DP时不能从小往大DP(或者写4维的),会重复计算。

     1 /**************************************************************
     2     Problem: 1004
     3     User: zhuohan123
     4     Language: C++
     5     Result: Accepted
     6     Time:152 ms
     7     Memory:1380 kb
     8 ****************************************************************/
     9  
    10 #include <iostream>
    11 #include <cstdio>
    12 #include <cstring>
    13 using namespace std;
    14 int sr,sg,sb,m,p,n;
    15 inline void add(int &a,int b){a=(a+b)%p;}
    16 int z[100],s[100],snum;
    17 bool ha[100];
    18 int f[30][30][30];
    19 int calc()
    20 {
    21     memset(f,0,sizeof f);
    22     memset(ha,0,sizeof ha);
    23     memset(s,0,sizeof s);
    24     snum=0;
    25     for(int i=1;i<=n;i++)
    26         if(!ha[i])
    27         {
    28             snum++;
    29             for(int j=i;!ha[j];j=z[j])ha[j]=true,s[snum]++;
    30         }
    31     f[0][0][0]=1;
    32     for(int i=1;i<=snum;i++)
    33         for(int r=sr;r>=0;r--)
    34         for(int g=sg;g>=0;g--)
    35         for(int b=sb;b>=0;b--)
    36         {
    37             if(r>=s[i])add(f[r][g][b],f[r-s[i]][g][b]);
    38             if(g>=s[i])add(f[r][g][b],f[r][g-s[i]][b]);
    39             if(b>=s[i])add(f[r][g][b],f[r][g][b-s[i]]);
    40         }
    41      
    42     return f[sr][sg][sb];
    43 }
    44 inline int sqr(int a){return a*a;}
    45 int exp(int a,int b,int p)
    46 {
    47     return b?sqr(exp(a,b/2,p))%p*((b&1)?a:1)%p:1;
    48 }
    49 int main(int argc, char *argv[])
    50 {
    51     scanf("%d%d%d%d%d",&sr,&sg,&sb,&m,&p);
    52     n=sr+sg+sb;
    53     int ans=0;
    54     for(int time=1;time<=m;time++)
    55     {
    56         for(int i=1;i<=n;i++)scanf("%d",&z[i]);
    57         add(ans,calc());
    58     }
    59     for(int i=1;i<=n;i++)z[i]=i;
    60     add(ans,calc());
    61     ans*=exp(m+1,p-2,p);ans%=p;
    62     printf("%d
    ",ans);
    63     return 0;
    64 }
  • 相关阅读:
    20200917-1 每周例行报告
    20200917-2 词频统计
    20200910-1每周例行报告
    20200910-2 博客作业
    20200910-3 命令行和控制台编程
    第05组 团队Git现场编程实战
    第05组 团队项目-需求分析报告
    团队项目-选题报告
    第二次结对编程作业
    第一次结对编程作业
  • 原文地址:https://www.cnblogs.com/zhuohan123/p/3271060.html
Copyright © 2011-2022 走看看