传送门:http://poj.org/problem?id=1286
继上次的Burnside引理后面提出的疑问,我们来说一下polya
这是polya的主要内容:
![]()
(来自百度百科)
我们可以发现polya和burnside求解的问题是一样的,都是求等价类的数目,但是burnside需要把所有的情况求出来,但是如果我们有循环节数和置换数就可以使用polya在很快的时间内求解。
那么对于这一题,颜色的数目是一定的(3种)
那么我们就只需要计算循环节。
对于旋转和翻转我们都要计算。
旋转:有n种置换,设旋转长度为i,则循环节长度为gcd(n,i)
翻转:奇数时,对称轴穿过珠子,一共n条。对称轴上的一个珠子构成一个循环,其他n-1个珠子分别以对称轴对称构成(n-1)/2个循环,所以循环节的个数是1+(n-1)/2=(n+1)/2 。
偶数时,对称轴可能穿过两个珠子,一共 n/2条,对称轴上的两个珠子构成两个循环,其他n-2个珠子分别以对称轴对称构成(n-2)/2个循环。还有一种情况,对称轴穿过两个珠子之间,这时候其他的珠子都两两对称,构成n/2个循环。
注意!同时考虑了旋转和翻转后,置换群的个数是2n。
code:
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
typedef long long ll;
ll gcd(ll a,ll b){return b==0?a:gcd(b,a%b);}
ll powmod(ll a,ll b)
{
ll ans=1;
while(b!=0)
{
if(b&1) ans=ans*a;
a=a*a;
b>>=1;
}
return ans;
}
int main()
{
ll n,i,ans;
while(scanf("%lld",&n)!=EOF)
{
if(n==-1) break;
if(n==0){printf("0\n"); continue;}
ans=0;
for(int i=0;i<n;i++) ans+=powmod(3,gcd(n,i));
if(n%2==1)
{
ans+=n*powmod(3,(n+1)/2);
}
else if(n%2==0)
{
ans+=(n/2)*powmod(3,n/2);
ans+=(n/2)*powmod(3,(n-2)/2+2);
}
printf("%lld\n",ans/(n*2));
}
return 0;
}