思路:
置换:【1,2,…,n | a1, a2,…an】 表示1被a1取代(a1为1到n的某数),2被a2取代……, a1,a2…,an不相同
置换群:置换群的元素是置换,运算时置换的连接。例如:【1,2,3,4 | 3,1,2,4】【1,2,3,4 | 4,3,2,1】 = 【1,2,3,4 | 2,4,3,1】
轮换:记(a1a2…an) = 【a1,a2,a3,…an | a2,a3,…,an,a1】
方案与方案之间其实是可以看做一种置换,即由其中一种方案通过置换可以变成另一种方案。例如有4个珠子,2种颜色,我们看一下前两个珠子白色,后两个黑色的情况。这种方案可以通过置换【2,3,4,1】可以变成第一个和第四个是黑色,第二个和第三个为白色的方案;
Burnside引理:
置换会使一个着色方案变成另一个方案。但是有些方案比较特殊,他在某些置换下会置换到他自身。我们称之在置换f下不变。记C(f)为置换f下保持不变的着色方案个数。那么就有一个结论:本质不同的着色方案数为所有置换f的C(f)值的平均数。
我们设f的置换群为G,则Burnside引理:等价类数目 N = sum{C(f)} / |G|, f属于G。
这个公式虽然简单,但是对于C(f)的求解还是个问题,于是介绍下面的定理。
Polya定理:
利用置换论中轮换的概念(轮换概念=循环概念),我们将置换f分解为若干循环。记f的循环节数位m(f)。
则有定理:C(f) = k ^ m(f) ,其中k为着色数。
于是有Polya定理:不同的着色方案数 l = sum(k ^ m(f)) / |G| ,其中f属于G。
对于本题还有如下结论:
在此种模型下,所有的置换可以通过一个置换旋转和翻转全部得来。
(1)旋转
将置换顺时针旋转i格,其循环节数的为gcd(n, i);
(2)翻转
当n为奇数:共有n个循环节数为(n+1)/2的循环群
当 n为偶数:共有n/2个循环节数(n+2)/2的循环群,和n/2个循环节数n/2的循环群。
置换:【1,2,…,n | a1, a2,…an】 表示1被a1取代(a1为1到n的某数),2被a2取代……, a1,a2…,an不相同
置换群:置换群的元素是置换,运算时置换的连接。例如:【1,2,3,4 | 3,1,2,4】【1,2,3,4 | 4,3,2,1】 = 【1,2,3,4 | 2,4,3,1】
轮换:记(a1a2…an) = 【a1,a2,a3,…an | a2,a3,…,an,a1】
方案与方案之间其实是可以看做一种置换,即由其中一种方案通过置换可以变成另一种方案。例如有4个珠子,2种颜色,我们看一下前两个珠子白色,后两个黑色的情况。这种方案可以通过置换【2,3,4,1】可以变成第一个和第四个是黑色,第二个和第三个为白色的方案;
Burnside引理:
置换会使一个着色方案变成另一个方案。但是有些方案比较特殊,他在某些置换下会置换到他自身。我们称之在置换f下不变。记C(f)为置换f下保持不变的着色方案个数。那么就有一个结论:本质不同的着色方案数为所有置换f的C(f)值的平均数。
我们设f的置换群为G,则Burnside引理:等价类数目 N = sum{C(f)} / |G|, f属于G。
这个公式虽然简单,但是对于C(f)的求解还是个问题,于是介绍下面的定理。
Polya定理:
利用置换论中轮换的概念(轮换概念=循环概念),我们将置换f分解为若干循环。记f的循环节数位m(f)。
则有定理:C(f) = k ^ m(f) ,其中k为着色数。
于是有Polya定理:不同的着色方案数 l = sum(k ^ m(f)) / |G| ,其中f属于G。
对于本题还有如下结论:
在此种模型下,所有的置换可以通过一个置换旋转和翻转全部得来。
(1)旋转
将置换顺时针旋转i格,其循环节数的为gcd(n, i);
(2)翻转
当n为奇数:共有n个循环节数为(n+1)/2的循环群
当 n为偶数:共有n/2个循环节数(n+2)/2的循环群,和n/2个循环节数n/2的循环群。
Polya定理是个非常实用的定理,记p为格子数,s为着色数,则它可以在O(ps)内结果着色问题。
<span style="font-family:Arial;">/*
以后遇到累乘与幂用double或者long long
输出的技巧就是</span>%.0lf
<span style="font-family:Arial;">*/</span>
#include<stdio.h>
#include<math.h>
int gcd(int a,int b)
{
return b==0?a:gcd(b,a%b);
}
double polya(double k,int n)
{
int i;
double ans=0;
for(i=0;i<n;i++)
ans+=pow(k,gcd(n,i));
if(n%2)
ans+=n*pow(k,n/2+1);
else
{
ans+=(n/2)*pow(k,n/2+1);
ans+=(n/2)*pow(k,n/2);
}
return ans/(2*n);//G<span style="font-family:Arial;">中置换群的个数,n个旋转,n个翻转</span>
}
int main()
{
int s;
int c;
while(scanf("%d",&c)&& c!=-1)
if(c==0)
printf("0\n");
else
printf("%.0lf\n",polya(3,c));
return 0;
}