poj 1286 polya 定理

题意:用三种颜色的珠子串成长度为N(N<24)的项链,经过旋转和翻转所得的项链视为同一种项链,求共能组成几条不同的项链。

分析: 

1、旋转:置换的个数是n个,第i个置换的循环节个数是gcd(n,i)个。

证明:经过 LCM ( i  ,n ) / i 次旋转回到自身,循环节的长度是 LCM( i , n ) / i ,n / ( LCM( i , n ) / i )就是循环节的个数,n / ( LCM( i , n ) / i ) = gcd( n , i ) 

2、翻转:找循环节的关键是找对称轴,n要分奇偶性。

当n = 2 * k + 1,对称轴就是每个点和圆心的连线,共n条,除了这个点没变,其他的点都跟对称的那个点置换了,所以循环节的个数是k+1。

当n = 2 * k,对称轴是每个点和对面的点的连线,共k条,除了对称轴上的两个点,其余点都跟对面的点置换了,循环节的个数是k+1,

两个相邻点的中点和圆心的连线也是k条,每个点都跟对面的点置换了,循环节的个数是k,对称轴一共也是n条。

 

 

const int maxn = 30;
LL pow3[maxn] = {1};

void init(){
    FOR(i,1,maxn) pow3[i] = pow3[i-1] * 3;
}

int gcd(int x, int y){
     if (!x || !y) return x + y;
     for (int t; t = x % y; x = y, y = t);
     return y;
}

int n, k;
LL ans;

void polya(){
    ans = 0;  k = n>>1;

    if(n&1) ans += n * pow3[k+1];   //翻转
    else ans += k * (pow3[k+1] + pow3[k]);

    ans += pow3[n]; //旋转0
    FOR(i,1,n){     //旋转i
        int t = gcd(i, n);
        ans += pow3[t];
    }

    ans /= n<<1 ;
    cout<<ans<<endl;
}

int main(){
    #ifndef ONLINE_JUDGE
    freopen("in.txt","r",stdin);
    //freopen("out.txt","w",stdout);
    #endif

    init();

    while( cin>>n, n != -1 ){
        if( n == 0) {cout<<0<<endl;continue;}
        polya();
    }

    return 0;
}

 

转载于:https://www.cnblogs.com/ts65213/archive/2013/05/02/3054890.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值