题目链接:
http://poj.org/problem?id=2409
题目大意:
给定M种颜色的珠子,每种颜色珠子的个数均不限,将这些珠子做成长度为N的项链。
问能做成多少种不重复的项链,最后的结果不会超过int类型数据的表示范围。并且两
条项链相同,当且仅当两条项链通过旋转或是翻转后能重合在一起,且对应珠子的颜
色相同。
解题思路:
Polya定理的应用。先来看Polya定理。
Polya定理:设 G = {a1,a2,…,ag}是 N 个对象的置换群,用 M 种颜色给这 N 个
对象着色,则不同的着色 方案数为:
|G|^(-1) * {M^c(a1) + M^c(a2) + … + M^c(ag)}。
其中 c(ai)为置换 ai 的循环节数,( i = 1,2,…,g )。
对于这道题,直接用Polya定理求解,找出所有的置换,并求出置换的循环节数。然后
根据上边公式求出 M^c(ai) 的总和,再除以置换群个数。
题中有两种置换方式:
1.旋转置换。分别顺时针旋转 i 个珠子,其循环节长度为 LCM(N,i) / i,循环节数为
N / (LCM(N,i) / i),即 GCD(N,i)。
2.翻转置换。根据 N 的奇偶性分情况讨论。
N为奇数时:
以第 i 个珠子为顶点和中心翻转,翻转后,第 i 个珠子保持不变,其余珠子两两相
互对换,因为有 N 个珠子,所以有 N 种翻转置换,每种翻转循环节数为 (N+1) / 2。
N为偶数时,有两种翻转方式:
以两边相对的两个珠子为轴和中心翻转,翻转后,这两个珠子保持不变,其余珠子
两两相互对换,共有 N/2 种翻转置换,每种翻转循环节数为 (N+2) / 2。
以相邻的珠子中间连线为轴和中心翻转,翻转后,所有珠子两两相互对换,共有 N/2
种翻转置换,每种翻转循环节数为 N/2。
然后根据Polya定理的公式和上述所求求出结果。
AC代码:
#include<iostream> #include<algorithm> #include<cstdio> #include<cstring> #include<cmath> using namespace std; int M,N; int GCD(int a,int b) { if(b == 0) return a; return GCD(b,a%b); } int main() { while(~scanf("%d%d",&M,&N) && (M||N)) { int sum = 0; for(int i = 1; i <= N; ++i) { int tmp = GCD(N,i); sum += (int)(pow(M*1.0,tmp*1.0)); } if(N & 1) sum += (int)(N * pow(M*1.0, (N+1)/2.0)); else { sum += (int)((N/2) * pow(M*1.0, (N+2)/2.0)); sum += (int)((N/2) * pow(M*1.0, N/2.0)); } sum = sum/(2*N); printf("%d\n",sum); } return 0; }
版权声明:本文为博主原创文章,未经博主允许不得转载。