首页 写随笔

cdcq(本博客废弃!现用博客:https://www.cnblogs.com/cdcq/)

本博客废弃!现用博客:https://www.cnblogs.com/cdcq/

导航

【BZOJ1004】【HNOI20008】cards

看黄学长的代码才写出来的,sro_hzwer_orz

原题:

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

m<=60,m+1<p<100,Max{Sr,Sb,Sg}<=20。

 

已经把置换给出来了,要么burnside,要么polya,然而这题颜色有使用限制,所以不能用polya(polya还没理解,这里还不懂)

所以就用burnside:一个置换群的等价计数=(每个置换的置换后等价情况数)/置换总数

置换后的等价情况数就是在置换中没变的数,这个很好写

然后在置换中没变的数要刷的颜色是一样的,只有三种颜色所以就可以搞个三维的01包计数

最后除的内个置换总数因为要膜,所以要用到除法逆元

怎么用呐:

bx mod p=1,x就是b模P的乘法逆元,呢么x≡1/b(mod p),呢么a/b≡ax(mod p),然后用扩展欧几里得求乘法逆元即可(就是解bx mod p=1,某年NOIPT1)

代码:

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<algorithm>
 4 #include<cstring>
 5 #include<cmath>
 6 using namespace std;
 7 int sr,sb,sg,n,m,p;
 8 int huan[110][110];
 9 bool visited[110];
10 int ge[110];
11 int f[110][110][110];
12 int ans=0;
13 void exgcd(int a,int b,int &x,int &y){
14     if(!b){  x=1,y=0;  return ;}
15     exgcd(b,a%b,x,y);
16     int t=x;  x=y;  y=t-a/b*y;
17 }
18 int dp(int x){
19     memset(visited,0,sizeof(visited));
20     int cnt=0,temp;
21     for(int i=1;i<=n;i++)if(!visited[i]){
22         visited[i]=true;
23         ge[++cnt]=1;  temp=i;
24         while(!visited[huan[x][temp]]){
25             ge[cnt]++;
26             visited[huan[x][temp]]=true;//这里容易蒙……
27             temp=huan[x][temp];//temp指向了这个连的下一个,再次循环时判断的是下一个的下一个……
28         }
29     }
30     memset(f,0,sizeof(f));  f[0][0][0]=1;
31     for(int t=1;t<=cnt;t++)
32         for(int i=sr;i>=0;i--)
33             for(int j=sb;j>=0;j--)
34                 for(int k=sg;k>=0;k--){
35                     if(i>=ge[t])  f[i][j][k]=(f[i][j][k]+f[i-ge[t]][j][k])%p;
36                     if(j>=ge[t])  f[i][j][k]=(f[i][j][k]+f[i][j-ge[t]][k])%p;
37                     if(k>=ge[t])  f[i][j][k]=(f[i][j][k]+f[i][j][k-ge[t]])%p;
38                 }
39     return f[sr][sb][sg];
40 }
41 int main(){//freopen("ddd.in","r",stdin);
42     cin>>sr>>sb>>sg>>m>>p;
43     n=sr+sb+sg;
44     for(int i=1;i<=m;i++)
45         for(int j=1;j<=n;j++)
46             scanf("%d",&huan[i][j]);
47     m++;
48     for(int i=1;i<=n;i++)  huan[m][i]=i;//注意还有不置换的情况
49     for(int i=1;i<=m;i++)
50         ans=(ans+dp(i))%p;
51     int x,y;
52     exgcd(m,p,x,y);
53     while(x<=0)x+=p;
54     cout<<ans*x%p<<endl;
55     return 0;
56 }
View Code

 

posted on 2016-09-27 10:29  cdcq_old  阅读(250)  评论(0编辑  收藏  举报