POJ 2409 Let it Bead Pólya定理

题目大意:给定一个n个点的环,可以旋转和翻转,要求涂上c种不同的颜色,问等价类数目

首先我们不考虑翻转 假设一次旋转k个位置 那么循环个数显然是Gcd(n,i)

现在考虑翻转 易知所有的置换都可以由【沿着某个固定的对称轴翻转】和【旋转】两步组成

观察一个环 比如我们将对称轴设定为1号节点与圆心的连线 一次旋转k个位置

那么每次置换x会被换到((n+2)-x+k-1)%n+1的位置

我们会发现置换两次之后x就回到了原位 

乍一看每个置换都是(AB)(CD)(EF)这样的形式 但是我们忽视了可能一个点置换后还在原点的情况

此时2x≡k+2 (mod n)

由于x<=n,因此等式成立只有两种情况:

2x=k+2 或 2x=n+k+2

当n为奇数时 k+2与n+k+2异号 两个等式中只有一个可以成立 置换是(A)(BC)(DE)(FG)的形式

当n为偶数时

如果k是奇数 那么k+2和n+k+2都是奇数 等式无解 置换是(AB)(CD)(EF)(GH)的形式

如果k是偶数 那么k+2和n+k+2都是偶数 等式有两个解 置换是(A)(B)(CD)(EF)(GH)的形式

因此对于每种置换我们都能求出循环的个数,用所有c的循环个数次幂之和除以置换数2n就是答案

注意n<=2时翻转与否是同一置换,因此每个置换被计算了两次,但是平均值不变,不影响答案

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
int n,c;
long long Quick_Power(long long x,long long y)
{
	long long re=1;
	while(y)
	{
		if(y&1) re*=x;
		x*=x; y>>=1;
	}
	return re;
}
int main()
{
	int i;
	while(cin>>c>>n,c||n)
	{
		long long ans=0;
		for(i=0;i<n;i++)
		{
			ans+=Quick_Power(c,__gcd(n,i));
			if(n&1)
				ans+=Quick_Power(c,n+1>>1);
			else
				ans+=Quick_Power(c,(n>>1)+(~i&1));
		}
		cout<<ans/2/n<<endl;
	}
	return 0;
}


你可能感兴趣的:(poj,polya定理,群论,POJ2409)