poj2409 Let it Bead polya定理

来源:互联网 发布:骨科医生 知乎 编辑:程序博客网 时间:2024/06/08 00:14

题意:用k种颜色对n个珠子构成的环上色,旋转翻转后相同的只算一种,求不等价的着色方案数。

思路:polya定理。

考虑旋转:有n种置换,其中向右旋转i格,产生gcd(n,i)个循环节,ans+=pow(k,gcd(n,i))。

考虑翻转:

若n为奇数,有n种翻转置换,每种翻转都是以一个顶点和该顶点对边的中点对称,产生(n+1)/2个循环节。ans+=pow(k,(n+1)/2)*n。

若n为偶数,有n种翻转置换,其中一半是以两个对应顶点,另一半是以两条对边对称,分别产生(n+2)/2个循环节和n/2个循环节。

ans+=pow(k,(n+2)/2)*n/2+pow(k,n/2)*n/2。

最后用ans/=(2*n)。因为无论奇偶,都是有2*n个置换。详见代码:

// file name: poj2409.cpp //// author: kereo //// create time:  2014年09月05日 星期五 00时33分25秒 ////***********************************//#include<iostream>#include<cstdio>#include<cstring>#include<queue>#include<set>#include<map>#include<vector>#include<stack>#include<cmath>#include<algorithm>using namespace std;typedef long long ll;const int MAXN=10000+100;const int inf=0x3fffffff;#define L(x) (x<<1)#define R(x) (x<<1|1)int n,k;int gcd(int a,int b){return b == 0 ? a: gcd(b,a%b);}ll num_pow(ll a,int k){ll ans=1;while(k){if(k&1)ans*=a;a*=a;k>>=1;}return ans;}int main(){while(~scanf("%d%d",&k,&n) && n+k){ll ans=0;for(int i=1;i<=n;i++)ans+=num_pow(k,gcd(n,i));if(n&1)ans+=num_pow(k,(n+1)/2)*n;else{ ans+=num_pow(k,(n+2)/2)*n/2;ans+=num_pow(k,n/2)*n/2;}printf("%lld\n",ans/(2*n));}return 0;}


0 0
原创粉丝点击