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\n",ans);

63     return 0;

64 }

 

你可能感兴趣的:(2008)