题意: 分给出a,b,c个颜色各不相同的珠子,穿成一条长度为a+b+c的项链,在翻转和旋转的条件下,能够形成多少等价类。
分析: 这题有数量限制,所以直接搬Polya公式不行,需要用到Burnside的定理L = (Z1 + Z2 + .... Zk) / |G| (Zk为置换gk(gk∈G)的方案个数)。染色方案个数 = 经过有限次置换运算后,染色结果不变的方案个数之和。
每一个置换环中的元素染色应该是一样的,这句话至关重要。因为他保证了经过置换运算后,染色结果不变。
这里的每种颜色内部的珠子都是一样的,但置换环之间是不一样的
#include<iostream> #include<cstdio> #include<cstring> using namespace std; #define LL long long LL C[44][44]; void init() { memset(C,0,sizeof(C)); C[0][0] = C[1][0] = C[1][1] = 1; LL up=40; for(LL i=2; i<=up; i++) { C[i][0] = 1; for(LL j=1; j<=up; j++) { C[i][j] = C[i-1][j]+C[i-1][j-1]; } } } LL gcd(LL a,LL b) { if(b==0) return a; else return gcd(b,a%b); } int main() { init(); LL T,a,b,c; scanf("%lld",&T); while(T--) { scanf("%lld%lld%lld",&a,&b,&c); LL n = a+b+c; ///考虑旋转 LL ans = 0; for(LL i=1; i<=n; i++) { LL x = gcd(i,n); LL L = n/x; if(a%L || b%L || c%L) continue; LL a1=a/L,b1=b/L,c1=c/L; ans = ans + C[x][a1]*C[x-a1][b1]; } // printf("ans1 = %lld ",ans); ///考虑翻转 LL odd = 0; if(a&1) odd++; if(b&1) odd++; if(c&1) odd++; if(n&1) { if(odd == 1) { ///n个(x)(xx)(xx).....(xx)的置换 LL aa,bb,cc; if(a&1) { aa=a; bb=b; cc=c; } else if(b&1) { aa=b; bb=a; cc=c; } else { aa=c; bb=a; cc=b; } aa = (aa-1)>>1; bb = bb>>1; LL x = (n-1)>>1; ans = ans + n*C[x][aa]*C[x-aa][bb]; } } else { if(odd == 2){ ///n/2个(x)(x)(xx)....(xx)形式的置换 LL aa,bb,cc; if(!(c&1)){ aa=a; bb=b; cc=c; }else if(!(b&1)){ aa=a; bb=c; cc=b; }else { aa=b; bb=c; cc=a; } aa = (aa-1)>>1; bb = (bb-1)>>1; LL x = (n-2)>>1; ans = ans + n*C[x][aa]*C[x-aa][bb]; }else if(odd == 0){ LL aa=a>>1,bb=b>>1,cc=c>>1; LL x = n>>1; ///n/2个(x)(x)(xx)....(xx)形式的置换 LL tmp[3]; for(LL i=0;i<3;i++){ for(LL j=0;j<3;j++){ tmp[0]=a; tmp[1]=b; tmp[2]=c; tmp[i]--; tmp[j]--; if(tmp[i]<0||tmp[j]<0) continue; LL Left = (n-2)>>1; bool ok = true; for(LL k=0;k<3;k++){ if((tmp[k]&1)){ ok = false; break; } tmp[k]>>=1; } if(ok==false) continue; ans = ans + (n>>1)*C[Left][tmp[0]]*C[Left-tmp[0]][tmp[1]]; } } ///n/2个(xx)(xx).....(xx)形式的置换 ans = ans + (n>>1)*C[x][aa]*C[x-aa][bb]; } } // printf("ans2 = %lld ",ans); printf("%lld ",ans/(n<<1)); } return 0; }/** 100 0 4 0 0 5 0 0 5 5 4 0 4 4 0 5 */