15145641

  题意: 分给出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\n",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\n",ans);
        printf("%lld\n",ans/(n<<1));
    }
    return 0;
}/**
100
0 4 0
0 5 0
0 5 5
4 0 4
4 0 5
*/
View Code

 

posted on 2017-11-23 14:23  icode-xiaohu  阅读(340)  评论(0编辑  收藏  举报