HDU1817 Necklace of Beads【Polya定理】

题目链接:

http://acm.hdu.edu.cn/showproblem.php?pid=1817


题目大意:

给定3种颜色的珠子,每种颜色珠子的个数均不限,将这些珠子做成长度为N的项链。

问能做成多少种不重复的项链,最后的结果不会超过int类型数据的表示范围。并且两

条项链相同,当且仅当两条项链通过旋转或是翻转后能重合在一起,且对应珠子的颜

色相同。


解题思路:

这道题和POJ2409是一样的题目,只不过这道题规定了颜色数目。

Polya定理的应用。先来看Polya定理。

Polya定理:设 G = {a1,a2,…,ag}是 N 个对象的置换群,用 M 种颜色给这 N 个

对象着色,则不同的着色 方案数为:

                  |G|^(-1) * {M^c(a1) + M^c(a2) + … + M^c(ag)}。

其中 c(ai)为置换 ai 的循环节数,( i = 1,2,…,g )。

对于这道题,直接用Polya定理求解,找出所有的置换,并求出置换的循环节数。然后

根据上边公式求出 3^c(ai) 的总和,再除以置换群个数。

题中有两种置换方式:

1.旋转置换。分别顺时针旋转 i 个珠子,其循环节长度为 LCM(N,i) / i,循环节数为

N / (LCM(N,i) / i),即 GCD(N,i)。

2.翻转置换。根据 N 的奇偶性分情况讨论。

N为奇数时:

       以第 i 个珠子为顶点和中心翻转,翻转后,第 i 个珠子保持不变,其余珠子两两相

互对换,因为有 N 个珠子,所以有 N 种翻转置换,每种翻转循环节数为 (N+1) / 2。

N为偶数时,有两种翻转方式:

      以两边相对的两个珠子为轴和中心翻转,翻转后,这两个珠子保持不变,其余珠子

两两相互对换,共有 N/2 种翻转置换,每种翻转循环节数为 (N+2) / 2。

      以相邻的珠子中间连线为轴和中心翻转,翻转后,所有珠子两两相互对换,共有 N/2

种翻转置换,每种翻转循环节数为 N/2。

然后根据Polya定理的公式和上述所求求出结果。

注意:这道题用 int 的话3^18就已经超出 int 范围了,所以要用 __int64类型。


AC代码:

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<cmath>
#define LL __int64
using namespace std;

LL GCD(LL a,LL b)
{
    if(b == 0)
        return a;
    return GCD(b,a%b);
}

LL Pow(LL a, LL m)
{
    LL ans = 1;
    while(m)
    {
        if(m & 1)
            ans *= a;
        a *= a;
        m >>= 1;
    }
    return ans;
}
int main()
{
    LL N;
    while(~scanf("%I64d",&N) && N != -1)
    {
        if(N <= 0)
        {
            printf("0\n");
            continue;
        }
        LL sum = 0;
        for(int i = 1; i <= N; ++i)
        {
            LL tmp = GCD(N,i);
            sum += (LL)(Pow(3LL,tmp));
        }
        if(N & 1)
            sum += (LL)(N * Pow(3LL, (N+1)/2));
        else
        {
            sum += (LL)((N/2) * Pow(3LL, (N+2)/2));
            sum += (LL)((N/2) * Pow(3LL, N/2));
        }

        sum = sum/2/N;
        printf("%I64d\n",sum);
    }

    return 0;
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值