poj 2409 【Let it Bead】

/*

问题:给你m种不同颜色的珠子,你能穿出多少长度为n的“本质不同”首饰来。这里的“本质不同”指首饰经过翻转或旋转,不会与其他方案相同。我们称之为着色方案。例如图中给出的2种颜色,穿出5个珠子的首饰的各种方案示意图。 
思路: 
置换:【1,2,…,n | a1, a2,…an】 表示1被a1取代(a1为1到n的某数),2被a2取代……, a1,a2…,an不相同 
置换群:置换群的元素是置换,运算时置换的连接。例如:【1,2,3,4 | 3,1,2,4】【1,2,3,4 | 4,3,2,1】 = 【1,2,3,4 | 2,4,3,1】 
轮换:记(a1a2…an) = 【a1,a2,a3,…an | a2,a3,…,an,a1】 
方案与方案之间其实是可以看做一种置换,即由其中一种方案通过置换可以变成另一种方案。例如有4个珠子,2种颜色,我们看一下前两个珠子白色,后两个黑色的情况。这种方案可以通过置换【2,3,4,1】可以变成第一个和第四个是黑色,第二个和第三个为白色的方案; 
Burnside引理: 
置换会使一个着色方案变成另一个方案。但是有些方案比较特殊,他在某些置换下会置换到他自身。我们称之在置换f下不变。记C(f)为置换f下保持不变的着色方案个数。那么就有一个结论:本质不同的着色方案数为所有置换f的C(f)值的平均数。 
我们设f的置换群为G,则Burnside引理:等价类数目 N = sum{C(f)} / |G|, f属于G。 
这个公式虽然简单,但是对于C(f)的求解还是个问题,于是介绍下面的定理。 
Polya定理: 
设G是N个对象上的置换群,用M种颜色涂染这N个对象,则不同的染色方案数为: 
     LG =( Mλ(g1)+Mλ(g2)+…+Mλ(gp))/|G| 
其中G=(g1,g2, …gp), λ(gk)为置换gk的轮换的个数。 
利用置换论中轮换的概念(轮换概念=循环概念),我们将置换f分解为若干循环。记f的循环节数位m(f)。 
则有定理:C(f) = k ^ m(f) ,其中看为着色数。 
于是有Polya定理:不同的着色方案数 l = sum(k ^ m(f)) / |G| ,其中f属于G。 
对于本题还有如下结论: 
在此种模型下,所有的置换可以通过一个置换旋转和翻转全部得来。 
(1)旋转 
将置换顺时针旋转i格,其循环节数的为gcd(n, i); 
(2)翻转 
当n为奇数:共有n个循环节数为(n+1)/2的循环群 
当 n为偶数:共有n/2个循环节数(n+2)/2的循环群,和n/2个循环节数n/2的循环群。 
Polya定理是个非常实用的定理,记p为格子数,s为着色数,则它可以在O(ps)内结果着色问题。 

*/
#include<stdio.h>
#include<string.h>
#include<math.h>
#define inta __int64
int gcd(int x,int y){
    int r;
    if(y==0) return x;
    else r=x%y;
    return gcd(y,r);
}
int poww(int a,int b){
    int i,tmp;
    tmp=1;
    if(b==0) return 1;
    if(b==1) return a;
    for(i=1;i<=b;i++)
        tmp*=a;
    return tmp;
}
int main(){
    int n,m;
    int ans;
    while(scanf("%d %d ",&n,&m)!=EOF&&(n!=0||m!=0)){

        ans=0;
        for(int i=1;i<=m;i++){
            ans+=poww(n,gcd(i,m));
        }
        if(m&1){
            ans+=m*poww(n,m/2+1);
        }
        else{
            ans+=m/2*poww(n,m/2)+m/2*poww(n,m/2+1);
        }
        ans/=m*2;
        printf("%d\n",ans);
    }
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值