POJ 2154-Color(Polya定理-旋转 串项链)

Color
Time Limit: 2000MS Memory Limit: 65536K
Total Submissions: 10352 Accepted: 3368

Description

Beads of N colors are connected together into a circular necklace of N beads (N<=1000000000). Your job is to calculate how many different kinds of the necklace can be produced. You should know that the necklace might not use up all the N colors, and the repetitions that are produced by rotation around the center of the circular necklace are all neglected. 

You only need to output the answer module a given number P. 

Input

The first line of the input is an integer X (X <= 3500) representing the number of test cases. The following X lines each contains two numbers N and P (1 <= N <= 1000000000, 1 <= P <= 30000), representing a test case.

Output

For each test case, output one line containing the answer.

Sample Input

5
1 30000
2 30000
3 30000
4 30000
5 30000

Sample Output

1
3
11
70
629

Source

POJ Monthly,Lou Tiancheng

题目意思:

给定m种颜色的珠子,每种颜色的珠子个数不限,将它们串成长度为n的项链,计算一共能做成多少种不重复的项链。仅考虑旋转,不考虑翻转。

解题思路:

旋转,将项链顺时针旋转i格之后,其循环节数是gcd(n,i),计算出所有不同的着色方案。
枚举i会TLE,所以用欧拉函数优化,每个循环的长度L=N/gcd(i,N),结果是∑(Euler(L)×N^(L-1))%P。


#include<cstdio>
#include<cmath>
#include<vector>
#include<algorithm>
using namespace std;
int quick(int a,int b,int m )//a^b%m 快速幂取模
{
    int ans=1;
    a%=m;
    while(b)
    {
        if(b&1)
        {
            ans=(ans*a)%m;
            --b;
        }
        b/=2;
        a=a*a%m;
    }
    return ans;
}
int Euler(int n)//欧拉函数
{
    int i,ans=n;
    for(i=2; i*i<=n; ++i)
        if(n%i==0)
        {
            ans-=ans/i;
            while(n%i==0)
                n/=i;
        }
    if(n>1)
        ans-=ans/n;
    return ans;
}
int main()
{
#ifdef ONLINE_JUDGE
#else
    freopen("G:/cbx/read.txt","r",stdin);
    //freopen("G:/cbx/out.txt","w",stdout);
#endif
    int t;
    scanf("%d",&t);
    while(t--)
    {
        int n,p,ans=0;
        scanf("%d%d",&n,&p);
        int i;
        for(i=1; i*i<n; i++)
            if(n%i==0) //如果i是n的约数,则n/i也是n的约数,也要做同样的处理
            {
                ans=(ans+(Euler(n/i)%p)*quick(n,i-1,p))%p ;
                ans=(ans+(Euler(i)%p)*quick(n,n/i-1,p))%p ;
            }
        if(i*i==n) ans=(ans+(Euler(i)%p)*quick(n,i-1,p))%p ;
        printf("%d\n",ans);
    }
    return 0;
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值