首页 > 代码库 > poj2409:Let it Bead(置换群 polya定理)
poj2409:Let it Bead(置换群 polya定理)
题目大意:长度为n的项链,要染m种颜色,可以通过旋转或翻转到达的状态视为同一种,问有多少种染色方案。
学了一波polya定理,发现很好理解啊,其实就是burnside定理的扩展。
burnside定理告诉我们不同染色方案数是每种置换的不变元素个数除以置换总数,而polya定理就是在这个基础上用公式计算出置换的不变元素个数。而且polya定理非常好理解,我们要让元素不变,所以对于每个循环节我们要染一样的颜色,有m种颜色,c(pk)个循环节,于是每种置换的不变元素个数就是m^c(pk)。
对于这道题,有两种操作。
①旋转。有n种置换,分别是1次旋转1个珠子,2个,3个...n个。对于1次旋转i个珠子,我们要求出循环节数可以先求出循环长度,一个位置置换x次之后回到原位,所以x=n*y/i,要使x尽量小且为整数那么n*y只能是lcm(n,i),于是循环长度为lcm(n,i)/i,那么循环节数为总长除以循环长度,n/(lcm(n,i)/i)=gcd(n,i)【n*i/gcd(n,i)=lcm(n,i)】。所以1次旋转i个珠子的循环节数为gcd(n,i)。
②翻转。对于奇偶性分类讨论。
(1)n为奇数。对于每个点作为对称轴左右翻转,则共n个置换,循环节数(n+1)/2。
(2)n为偶数。
a.对于对称的两个点作为对称轴左右翻转。n/2个置换,循环节数(n+2)/2。
b.对于两个点中间的空格作为对称轴左右反转,n/2个置换,循环节数n/2。
则共n个置换。
所以不论奇偶总置换数为2n,答案为sum/2n。
#include<iostream> #include<cstring> #include<cstdlib> #include<cstdio> using namespace std; int n,m; int qp(int a,int b) { int t=1,y=a; while(b) { if(b&1)t*=y; y*=y; b>>=1; } return t; } int gcd(int a,int b){return b?gcd(b,a%b):a;} int main() { while(~scanf("%d%d",&m,&n)&&(m||n)) { int sum=0; for(int i=1;i<=n;i++)sum+=qp(m,gcd(n,i)); if(n&1)for(int i=1;i<=n;i++)sum+=qp(m,(n+1)/2); else for(int i=1;i<=n/2;i++)sum+=qp(m,(n+2)/2)+qp(m,n/2); printf("%d\n",sum/(2*n)); } }
poj2409:Let it Bead(置换群 polya定理)
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。