http://poj.org/problem?id=2154

大致题意:由n个珠子,n种颜色,组成一个项链。要求不同的项链数目。旋转后一样的属于同一种。结果模p。



n个珠子应该有n种旋转置换。每种置换的循环个数为gcd(i,n)。假设直接枚举i,显然不行。可是我们能够缩小枚举的数目。

改为枚举每一个循环节的长度L,那么对应的循环节数是n/L。所以我们仅仅需求出每一个L有多少个i满足gcd(i,n)= n/L。就得到了循环节数为n/L的个数。

重点就是求出这种i的个数。



令cnt = gcd(i,n) = n/L。

那么cnt | i。令i = cnt*t(0 <= t <= L)。

又 n = cnt * L ;

所以gcd(i,n) = gcd( cnt*t, cnt*L) = cnt。

满足上式的条件是 gcd(t,L) = 1。

而这种t 有Eular(L)个。

因此循环节个数是n/L的置换个数有Eular(L)个。

參考博客:http://blog.csdn.net/tsaid/article/details/7366708



代码中求欧拉函数是基于素数筛的,素数仅仅需筛到sqrt(1e9)就可以。我在筛素数的同一时候递推的记录了sqrt(1e9)以内的Eular(n),用phi[]表示。这样会快那么一点点。



#include <stdio.h>
#include <iostream>
#include <algorithm>
#include <set>
#include <map>
#include <vector>
#include <math.h>
#include <string.h>
#include <queue>
#include <string>
#include <stdlib.h>
#define LL long long
#define _LL __int64
#define eps 1e-8
#define PI acos(-1.0)
using namespace std; const int maxn = 35000;
const int INF = 0x3f3f3f3f; int n,p;
int ans;
int prime[maxn];
int flag[maxn];
int prime_num;
int phi[maxn]; int mod_exp(int a, int b, int c)
{
int res = 1;
a = a%c;
while(b)
{
if(b&1)
res = (res*a)%c;
a = (a*a)%c;
b >>= 1;
}
return res;
} //素数筛并记录maxn以内的Eular(n)。用phi[]表示
void get_prime()
{
memset(flag,0,sizeof(flag));
prime_num = 0;
phi[1] = 1;
for(int i = 2; i <= maxn; i++)
{
if(!flag[i])
{
prime[++prime_num] = i;
phi[i] = i-1;
} for(int j = 1; j <= prime_num && i*prime[j] <= maxn; j++)
{
flag[i*prime[j]] = 1;
if(i % prime[j] == 0)
phi[i*prime[j]] = phi[i] * prime[j];
else phi[i*prime[j]] = phi[i] * (prime[j]-1);
}
}
} int Eular(int n)
{
if(n < maxn)
return phi[n] % p;
//求大于maxn的Eular(n)
int res = n;
for(int i = 1; prime[i]*prime[i] <= n && i <= prime_num; i++)
{
if(n % prime[i] == 0)
{
res -= res/prime[i];
while(n%prime[i] == 0)
n = n/prime[i];
}
}
if(n > 1)
res -= res/n;
return res%p;
} int main()
{ int test;
get_prime();
scanf("%d",&test); while(test--)
{
scanf("%d %d",&n,&p);
ans = 0;
for(int l = 1; l*l <= n; l++)
{
if(l*l == n)
{
ans = (ans + Eular(l)*mod_exp(n,l-1,p))%p;
}
else if(n%l == 0) //循环节长度为l,那么n/l也是循环节长度
{
ans = (ans + Eular(l)*mod_exp(n,n/l-1,p))%p;
ans = (ans + Eular(n/l)*mod_exp(n,l-1,p))%p;
}
}
printf("%d\n",ans);
}
return 0;
}

最新文章

  1. 动手做第一个Chrome插件
  2. 使用jsonp跨域请求后可以获得数据,但是进入error方法,返回parseerror
  3. 如何绑定android点击事件--跳转到另一个页面并实现关闭功能?
  4. 查看macbook是多少位
  5. [转载] 理解 rto
  6. [HIve - LanguageManual] Subqueries
  7. linux应用程序地址布局
  8. Maven--生命周期和插件(四)
  9. 1.C语言关键字(auto break case char const swtich)
  10. C++一些注意点之异常处理
  11. 拿到阿里,网易游戏,腾讯,smartx的offer的过程 (转)
  12. james+javamail入门
  13. CodeForces 635C XOR Equation
  14. stm32 复位后 引起引脚的变化,输出电平引起的问题
  15. Vim入门学习之Vim解析
  16. Git命令行对照表
  17. Linux简介,虚拟机安装,网络设置,桌面和vim安装
  18. 基于.NET平台的Ocelot网关框架教程汇总
  19. ___树形菜单Ztree.js显示.
  20. 弹出框sweetalert插件的简单使用

热门文章

  1. tcpdump的使用以及参数详解
  2. (转载)springboot集成httpinvoker的客户端
  3. MyBatis学习总结(1)——MyBatis快速入门
  4. HDU 4035
  5. POJ 3664 Election Time 题解
  6. 换今日特价图片---轻开电子商务系统(企业入门级B2C站点)
  7. JS冒泡事件 与 事件捕获
  8. centos6.0 配置SVN
  9. 大量文件时使用ls
  10. KMP字符串查找算法