您的位置:首页 > 其它

POJ-2409-Let it Bead&&NYOJ-280-LK的项链

2015-08-20 21:35 661 查看

POJ-2409-Let it Bead&&NYOJ-280-LK的项链–pólya定理

pólya定理

设G是n个对象的一个置换群,用m种颜色填充这n个对象,当置换群所形成的等价类被视为相同填充时,不同填充方案共有:

L=1|G|(mc(g1)+mc(g2)+...+mc(gs))

其中,G={g1,g2,...,gs},|G|是置换操作的个数s,c(gi)是置换gi的循环节数

pólya定理 的证明各位可上wiki上查看,在此我对置换循环节循环节数进行说明:

置换

n个元素1, 2, …, n之间的一个置换1,2,3...,na1,a2,...,an 表示1被1到n中的某个数a1取代,2被1到n中的某个数a2取代,直到n被1到n中的某个数an取代,且a1,a2,...,an互不相同

例如本题中一个旋转置换”顺时针旋转1个珠子“对应如下置换

1,2,3,...,n−1,n2,3,4,...,n,1

循环及循环节数

设有序列1, 2, 3, 4, 置换操作为”顺时针旋转2个珠子“,则有如下置换公式:

1,2,3,43,4,1,2 3,4,1,21,2,3,4

可以发现两次置换后回到初始状态,这称为一个循环。并且3和1,2和4总是相互替换,我们可以将此置换描述为:{1, 3}{2, 4},一对大括号被称为一个循环节循环节的个数就称为循环节数

再例如如下置换公式:

1,2,3,4,53,5,4,1,2

就可被描述为: {1, 3, 4}{2, 5}

于本题中,置换群是旋转以及翻转,n个对象对应于n个珠子,m种颜色对应于珠子的不同颜色,不同的填充方案对应于不同的珠子串法,所以本题pólya定理适用,我们需要做的就是通过分析置换操作的个数、种类以及对应的循环节数,再利用利用公式得出L。

旋转

对于一条有n个珠子的项链,(逆时针旋转可被顺时针代替,反之亦然。为方便叙述,后文旋转统一为顺时针旋转)共有“旋转 0, 1, 2, …,n-1个珠子”这n个置换。假设置换操作为“旋转i个珠子”,显然在此旋转下必须至少移动(lmc代表最小公倍数) lmc(i, n) 个珠子才会回到初始状态,而 lmc(i, n) = i * n / gcd(i, n),所以对于每个珠子在此置换下共需移动 n / gcd(i, n) 个 i,也就是 n / gcd(i, n) 次置换才能回到初始位置,所以每个循环节的内都有 n / gcd(i, n) 个元素(或者说是珠子),所以循环节数为 n / (n / gcd(i, n)) = gcd(i, n)个。即 设置换操作为“旋转i个珠子”,循环节数为 gcd(i, n)。

翻转

对于一条有n个珠子的项链,虽然翻转操作的形式受n的奇偶性影响,但是置换的个数都只有n个:

奇数情况下,翻转对称轴唯一的选择就是处在一个珠子上,这样才能使得对称轴两边均有n/2(整数除法)个珠子可以相互交换,从而实现翻转。 由于有n个珠子,所以对称轴就有n个选择,所以奇数时翻转有n个置换操作。假设置换操作为“选择珠子i为对称轴进行翻转”,则有 (n-1)/2 个“有2个元素的循环节”,加上 1 个“只有一个元素(即处于对称轴上的珠子)的循环节”,共有 (n+1)/2 个循环节,即 设置换操作为“选择珠子i为对称轴进行翻转”,循环节数为 (n+1)/2。

偶数情况下,翻转对称轴有两种形式,共n个置换操作:

翻转对称轴上没有珠子,共有n/2个选择,对应n/2个置换操作。任意一个置换操作,有 n/2 个“有2个元素的循环节”,即循环节数为 n/2。

–翻转对称轴上有两个珠子,共有n/2个选择,对应n/2个置换操作。任意一个置换操作,有 (n-2)/2 个“有2个元素的循环节“,加上 2 个“只有一个元素(即处于对称轴上的珠子)的循环节”,共有 n/2 + 1 个循环节,即循环节数为 n/2 + 1。

所以本题共有 |G|=n+n=2n 个置换操作,旋转对应n个,翻转对应n个,每个置换对应的循环节数如上所述,代入公式即可得到L。

代码为poj2409。将输入m替换为3即是nyoj280的代码:

/*
* poj. 2409
* date. 2015.8.20
* 16ms 132kB
*/
#include <iostream>
#include <cstdio>
using namespace std;

long long qpow(int a, int n) {      //由于库函数pow()返回值为double, 所以这里用快幂重写
long long result = 1, base = a;
while (n) {
if (n&1) result *= base;
base *= base;
n >>= 1;
}
return result;
}
int gcd(int a, int b) {             //计算最大公约数
return b ? gcd(b, a%b) : a;
}
long long polya(int n, int m) {
if (n == 0) return 0;
long long sum = 1;
for (int i = 0; i < n; ++i)     //旋转
sum += qpow(m, gcd(i, n));
if (n&1)                        //翻转
sum += n * qpow(m, (n+1)/2);                    //奇数情况
else
sum += n/2 * (qpow(m, n/2) + qpow(m, n/2 + 1)); //偶数情况
return sum/(n*2);
}

int main(){
int n, m;
while (~scanf("%d %d", &m, &n) && n && m)
printf("%d\n", polya(n, m));

return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  poj polya 算法