【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 }