TT_last 原创,转载请注明。
polya定理不知道可先看潘震皓的 《置换群快速幂运算研究与探讨》,下面是根据论文所做的一些题目。
很裸的一道polya定理应用题目,
处理的状态有:一个点顺时针旋转 0 ~ n-1 个点
还有就是对称旋转的情况:
当n为偶数时:有两个对应的点相连线 和两条对应线段中点连线 分别形成的对称轴
当n为奇数时:仅有一个点与对应直线形成对称轴。
#include <iostream>
#include <cmath>
using namespace std;
int c,s;
int gcd(int a,int b)
{
if(b == 0) return a;
else return gcd(b,a%b);
}
int polya(int n,int m)
{
int ans,i;
__int64 tmp = 0;
for(i = 0;i < n;i ++)
{
tmp += pow(m*1.0,1.0*gcd(n,i)); //n个循环 移动多少位。
}
if(n&1)
{
tmp += n*pow(m*1.0,(n+1)/2.0); //n个循环 一个点与对应线段中点连线
}else
{
tmp += n/2*pow(m*1.0,n/2+1)+n/2*pow(m*1.0,n/2); //n个循环 分别为两个点连线 两条相对线段中点连线。
}
ans = tmp/(2*n);
return ans;
}
int main()
{
while(scanf("%d%d",&c,&s),c|s)
{
printf("%d\n",polya(s,c));
}
return 0;
}
/*
欧拉函数 + 快速幂 + 筛选质因数
*/
原本n很大,如果按照前面的做法去做 从1 ~ n,不断枚举,那肯定要tle,这里需要用欧拉函数优化一下。
根据polya定理:方案数(先不考虑取余):
for(i = 0;i < n;i ++)
ans += pow(n,gcd(n,i));
从中,如果我们提取相同的gcd(n,i) 和取得它们的个数,那么时间复杂度将会减少很多。
设 m = gcd(n,i);m可以肯定是n的因子,而m = gcd(n,i),的个数就是 1 = gcd(n/m,i/m)的i/m个数,
这个可以用欧拉函数来求 euler(n/i);然后再根据polya定理做一下也就可以了。
#include <iostream>
using namespace std;
const int maxn = 32000;
int n,m,tmp;
int p[maxn],num,a[400],b[400],ans;
bool sign[maxn];
void init()
{
int i,j;
num = 0;
p[num++] = 2;
for(i = 4;i < maxn;i += 2) sign[i] = true;
for(i = 3;i < maxn;i ++)
{
if(!sign[i])
{
p[num++] = i;
for(j = i*i;j < maxn;j += i)