看黄学长的代码才写出来的,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 #include2 #include 3 #include 4 #include 5 #include 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< <