uva-10294-Polya

这里说下Polya相关的知识点

1.置换

n个元素1,2,3...n之间的一个置换 \begin{pmatrix} 1 & 2 & 3& ... & n\\ a1&a2 & a3 & ... &an \end{pmatrix}  表示1被1到n中某个数a1取代,2被1到n中某个数a2取代,...直到n被1到n中某个数an取代,且a1,a2,...an互不相同。

n个元素则表示n阶置换,且共有n!个(1-n的全排列)。

2.置换乘法

设:   ,       

3.等价类

通过置换的变换操作后可以相等的元素属于同一个等价类。

4.Burnside引理

用D(aj)表示在置换aj下不变的元素的个数。L表示本质不同的方案数(即等价类的个数)。

则 L=\frac{1}{|G|}\sum D(aj)(L为D(aj)的平均值) 

一正方形分成4格,2着色,有多少种方案?其中,经过转动相同的图象算同一方案。

每个格子一共有两种颜色可以选择,所以共有右图16中图像。

对图中图像的置换可以分为以下四种:

不动:a1=(1)(2)…(16)   16种置换0°后都不变,即等价类为16

逆时针转90度 :a2=(1)(2)(3 4 5 6)(7 8 9 10) (11 12)(13 14 15 16)    置换后只有图1,2不变,即等价类为2

顺时针转90度 :a3=(1)(2)(6 5 4 3)(10 9 8 7)(11 12)(16 15 14 13)    置换后只有图1,2不变,即等价类为2

转180度:a4=(1)(2)(3 5)(4 6)(7 9)(8 10)(11)(12) (13 15)(14 16)    置换后只有图1,2,11,12不变,即等价类为4

由Burnside引理,共有(16+2+2+4)/4=6,也就是定义旋转0,90,180,270°后相同的方案数相同时,一共只有6个等价类也就是6种方案。

5.置换分解成循环的乘积

\begin{pmatrix} 1 &2 &3 &4 & 5\\ 3& 5 &1 & 4 & 2 \end{pmatrix}=\left ( 1 \right 3)\left ( 2 \right 5)\left ( 4 \right )

1->3,3->1是一个循环,2->5,5->2是一个循环,4->4是一个循环,任意一个置换都可以表示成循环的乘积

6.Polya定理

如果置换f分解成m(f)个循环的乘积,假设涂k种颜色,则这个置换的方案数为C(f)=k^{m(f)}

Polya定理:等价类的个数等于所有置换的C(f)的平均。

总结来说就是通过Burnside引理得出的Polya定理,Polya定理就是根据每个置换的循环的个数来求出每个等价类的方案数,最后求得总的方案数。这样比起来直接用Burnside引理更好计算,Polya是Burnside的优化。

再来看这个题:

首先这个题总的来分有两种置换,旋转和翻转,小的分有按照不同的对称轴翻转和按照不同的度数旋转。

旋转时:n不同置换也不同,要求出每个置换的循环的个数,我的方法是列出来几个然后找规律,发现置换i时的循环个数是gcd(i,n),而刘汝佳给出的是假设逆时针旋转i颗珠子,那么0,i,2i,3i....是一个置换含有的元素,这时你可以这样想,这就是在长度为n的线上等间距i最多能找出多少个点,那么当为i的置换时,这个置换含有的元素的个数就是gcd(i,n)个,那么n/gcd(i,n)就是一共有多少种置换,那么n/n/gcd(i,n)=gcd(i,n)就是每个置换的循环的个数。

翻转时:这个地方翻转分奇偶而且,偶数时要注意是以穿过珠子为对称轴还是以不穿过珠子的对称轴旋转(太菜了没想到这点QAQ)。

n为奇数时,只能以穿过珠子的对称轴翻转,那么有n个顶点,就有n个对称轴,所以就是n种置换,那么就有(n+1)/2个循环。

n为偶数时,当以穿过珠子的对称轴翻转时,有n/2个对称轴,所以是n/2种置换,有n/2个循环;当以不穿过珠子的对称轴翻转时,有n/2个对称轴,有n/2种置换,有n/2+1个循环。

#include <cstdio>
#include <vector>
#include <string>
#include <cstring>
#include <algorithm>
#include <queue>
#include <iostream>
#include <list>
#include <cmath>
#define INF 0x3f3f3f3f

using namespace std;

typedef long long int ll;
ll n,t;
ll p[55];

int main()
{
    while(scanf("%lld%lld",&n,&t)!=EOF)
    {
        ll ans1=0,ans2=0;
        p[0]=1;
        for(int i=1;i<=n;i++) p[i]=p[i-1]*t;//为了不发生精度损失,所以打表处理幂次
        if(n%2)
            ans1+=n*p[(n+1)/2];
        else
            ans1+=n/2*(p[n/2]+p[n/2+1]);
        for(ll i=0;i<n;i++)
            ans2+=p[__gcd(i,n)];
        printf("%lld %lld\n",ans2/n,(ans2+ans1)/(2*n));
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/alusang/article/details/81487544