poj 1286 polya计数

polya 计数,首先算出有多少种旋转方式,n个点串成环,
如果旋转的话有n种;
其次,如果n为偶数,可以沿着两个顶点翻转,或者沿着
两个顶点之间翻转,  总的加一起是2*n种,同理,奇数
算出来也是2*n中,对于每种翻转,需要求循环节的个数
普通旋转的时候 如果旋转k(0<=k<=n-1)那么 循环节个数
是gcd(k,n),这是因为:在每次旋转k个单位的时候看看要
经过旋转多少次能归回原位,比如是x次。
那么x*k%n=0 所以 x*k=y*n 令x=n,y=k,所以x的最小值为
n/gcd(n,k),那么循环节个数为 n/(n/gcd(n,k))=gcd(n,k)
至于旋转画画就可以了

#include <iostream>
#include <cstdio>
using namespace std;
typedef long long ll;
ll quick_pow(ll a,ll n)   //log(n)  计算a^n
{
    ll ans=1,base=a;
    while(n!=0){
        if(n&1!=0)
            ans*=base;
        base*=base;
        n>>=1;
    }
    return ans;
}
ll gcd(ll a,ll b)
{
    return a==0?b:gcd(b%a,a);
}
int main()
{
    ll n;
    ll first,second;
    while(scanf("%lld",&n)!=EOF)
    {
        if(n==0)
        {
            printf("0\n");
            continue;
        }
        first=second=0;
        if(n==-1) break;
        if(n%2==0)
        {
            second=2*n;
            first+=quick_pow(3,n);
            for(int i=1;i<n;i++)
                first+=quick_pow(3,gcd(i,n));
            first+=n/2*quick_pow(3,n/2);
            first+=n/2*quick_pow(3,n/2+1);
        }
        else
        {
            second=2*n;
            first+=quick_pow(3,n);
            for(int i=1;i<n;i++)
                first+=quick_pow(3,gcd(i,n));
            first+=n*quick_pow(3,(n+1)/2);
        }
        printf("%lld\n",first/second);
    }
    return 0;
}
/*
polya 计数,首先算出有多少种旋转方式,n个点串成环,
如果旋转的话有n种;
其次,如果n为偶数,可以沿着两个顶点翻转,或者沿着
两个顶点之间翻转,  总的加一起是2*n种,同理,奇数
算出来也是2*n中,对于每种翻转,需要求循环节的个数
普通旋转的时候 如果旋转k(0<=k<=n-1)那么 循环节个数
是gcd(k,n),这是因为:在每次旋转k个单位的时候看看要
经过旋转多少次能归回原位,比如是x次。
那么x*k%n=0 所以 x*k=y*n 令x=n,y=k,所以x的最小值为
n/gcd(n,k),那么循环节个数为 n/(n/gcd(n,k))=gcd(n,k)
至于旋转简单画画就可以了
*/

猜你喜欢

转载自blog.csdn.net/hyacinthhome/article/details/81536240