zoukankan      html  css  js  c++  java
  • UVA 11255 Necklace (BurnSide定理)

      题意: 分给出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
    */
    View Code
  • 相关阅读:
    sql over(partition by) 开窗函数的使用
    利用curl函数处理GET数据获取微信公众号的access_token
    2018.4.12
    字段和属性
    C#实现回车键登录
    判断DataTable里面数据是否有重复数据
    一个强大的人民币大写转换的正则表达式
    C#将image中的显示的图片转换成二进制
    遍历Dev LayoutControl中的所有控件信息
    遍历窗体中所有控件的信息
  • 原文地址:https://www.cnblogs.com/jifahu/p/7884719.html
Copyright © 2011-2022 走看看