关于polya定理:n个珠子,t种颜色,手镯的种数:
(1)旋转:逆时针旋转i颗珠子的间距,则珠子0,、i、2i、......构成一个循环。这个循环有n/gcd(i,n)个元素。根据对称性,所有循环的长度均相同,因此一共有gcd(i,n)个循环。这些置换的不动点总数为a=t^gcd(i,n) 求和,i从0~n-1。
(2)翻转:需要分两种情况讨论。当n为奇数时,对称轴有n条,每条对称轴形成(n-1)/2个长度为2的循环和1个长度为1的循环,即(n+1)/2个循环。这些置换的不动点总数为b=nt^((n+1)/2)。当n为偶数时,有两种对称轴。穿过珠子的对称轴有n/2条,各形成n/2-1个长度为2的循环和两个长度为1的循环;不穿过珠子的对称轴有n/2条,各形成n/2个长度为2的循环。这些置换的不动点总数为b=n/2(t^(n/2+1)+t^(n/2))。
项链总数为a/n,手镯总数为(a+b)/2n。
#include <iostream>
#include <fstream>
#include <algorithm>
#include <cstring>
using namespace std;
#define N 32
int c,s;
int pow[N+5];
int gcd(int i,int j)
{
while (i%j) {
int tmp=j;
j=i%j;
i=tmp;
}
return j;
}
void polya()
{
pow[0]=1;
for (int i=1;i<=s;i++) pow[i]=pow[i-1]*c;
int a,b;
a=b=0;
for (int i=0;i<s;i++) a+=pow[gcd(i,s)];
if (s%2) b=s*pow[(s+1)/2];
else b=s/2*(pow[s/2+1]+pow[s/2]);
printf("%d\n",(a+b)/2/s);
}
int main()
{
freopen("data.in","r",stdin);
//freopen("data.out","w",stdout);
scanf("%d%d",&c,&s);
while (!(c==0 && s==0)){
polya();
scanf("%d%d",&c,&s);
}
return 0;
}