Burnside引理
百度百科的定义:
设G=a1,a2,…ag是目标集[1,n]上的置换群。每个置换都写成不相交循环的乘积。 是在置换ak的作用下不动点的个数,也就是长度为1的循环的个数。通过上述置换的变换操作后可以相等的元素属于同一个等价类。若G将[1,n]划分成l个等价类,则:
其中c(ai) 就是对应不动点的个数
Polya定理
假设一个置换有k个循环,易知每个循环对应的所有位置颜色需一致,而任意两个循环之间选什么颜色互不影响。因此,如果有m种可选颜色,则该置换对应的不动点个数为mk。用其替换burnside引理中的C(f),即C(f)=mk
。得到等价类数目为:
挑战程序设计竞赛中302页有较为详细的介绍
∑|F|i=0mki|F| ,的
这里来
#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
#define ll long long
int gcd(int m,int i)
{
if(i==0) return m;
return gcd(i,m%i);
}
ll quick(ll m,ll i)
{
ll ans=1;
while(i)
{
if(i&1) ans=ans*m;
i>>=1;
m=m*m;
}
return ans;
}
int main()
{
int n;
while(~scanf("%d",&n))
{
if(n==-1) break;
if(n==0){
cout<<"0"<<endl;continue;
}
ll ans=0;
for(int i=1;i<=n;i++)
ans+=quick(3,gcd(i,n));
if(n&1) ans+=n*quick(3,1+n/2);
else ans+=(n/2)*quick(3,n/2)+(n/2)*quick(3,n/2+1);
ans=ans/(2*n);///注意除以2*n,循环有n个置换,翻转有n个置换
printf("%lld\n",ans);
}
return 0;
}