poj2409 等价类计数问题 polya定理


关于polya定理:n个珠子,t种颜色,手镯的种数:

(1)旋转:逆时针旋转i颗珠子的间距,则珠子0,、i、2i、......构成一个循环。这个循环有n/gcd(i,n)个元素。根据对称性,所有循环的长度均相同,因此一共有gcd(i,n)个循环。这些置换的不动点总数为a=t^gcd(i,n) 求和,i从0~n-1。

(2)翻转:需要分两种情况讨论。当n为奇数时,对称轴有n条,每条对称轴形成(n-1)/2个长度为2的循环和1个长度为1的循环,即(n+1)/2个循环。这些置换的不动点总数为b=nt^((n+1)/2)。当n为偶数时,有两种对称轴。穿过珠子的对称轴有n/2条,各形成n/2-1个长度为2的循环和两个长度为1的循环;不穿过珠子的对称轴有n/2条,各形成n/2个长度为2的循环。这些置换的不动点总数为b=n/2(t^(n/2+1)+t^(n/2))。

项链总数为a/n,手镯总数为(a+b)/2n。


#include <iostream>
#include <fstream>
#include <algorithm>
#include <cstring>
using namespace std;
#define N 32

int c,s;
int pow[N+5];

int gcd(int i,int j)
{
    while (i%j) {
        int tmp=j;
        j=i%j;
        i=tmp;
    }
    return j;
}

void polya()
{
    pow[0]=1;
    for (int i=1;i<=s;i++) pow[i]=pow[i-1]*c;
    int a,b;
    a=b=0;
    for (int i=0;i<s;i++) a+=pow[gcd(i,s)];
    if (s%2) b=s*pow[(s+1)/2];
    else b=s/2*(pow[s/2+1]+pow[s/2]);
    printf("%d\n",(a+b)/2/s);
}

int main()
{
    freopen("data.in","r",stdin);
    //freopen("data.out","w",stdout);
    scanf("%d%d",&c,&s);
    while (!(c==0 && s==0)){
        polya();
        scanf("%d%d",&c,&s);
    }
    return 0;
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值