您的位置:首页 > 移动开发

poj 2773 Happy 2006(数论:欧拉函数)

2014-08-19 23:36 351 查看
给出n, k,输出与n互质的第k个正整数

这个题归根结底用到了一个性质:

gcd(a, b) == gcd(a, b+a*t)
(t=0,1,2...)

所以一种方法就是找到小于n且与n互质的所有数prime[]以及其个数cnt

如果k<tot,则直接输出

否则根据上式可知存在循环节,相邻两个循环节之间相差:k/cnt*m

所以结果应该为:k/cnt*m+prime[k%(cnt-1)]

但是还要考虑一种情况k%cnt == 0

此时结果应该为:(k/cnt-1)*m+prime[cnt-1];

暴力求素数2407打表代码如下:

#include <cstdio>
#include <iostream>
#define MAXN 1001000
using namespace std;

int prime[MAXN];

int gcd(int a, int b) {
return b ? gcd(b, a%b) : a;
}

int main(void) {
int m, k, i, cnt;
while(scanf("%d%d", &m, &k) != EOF) {
cnt = 0;
for(i=1; i<=m; ++i)
if(gcd(m, i) == 1)
prime[cnt++] = i;
if(k % cnt)
cout << k/cnt*m+prime[k%cnt-1] << endl;
else cout << (k/cnt-1)*m+prime[cnt-1] << endl;
}
return 0;
}


而上面用到了求n以内与n互质的数以及个数

所以很容易想到用欧拉函数

这个题用欧拉函数要快的多得多

16ms代码如下:

#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#define MAXN 1001000
using namespace std;

int prime[MAXN];
bool vis[MAXN];

int euler_phi(int n) {
int m, cnt, ans, tmp;
m = sqrt(n+0.5);
cnt = 0;
ans = tmp = n;
for(int i=2; i<=m; ++i) {
if(n%i == 0) {
prime[cnt++] = i;
ans = ans/i*(i-1);
n /= i;
while(n%i == 0)
n /= i;
for(int j=i; j<=tmp; j+=i)
vis[j] = true;
}
}
if(n > 1) {
ans = ans/n*(n-1);
for(int j=n; j<=tmp; j+=n)
vis[j] = true;
}
return ans;
}

int get(int n) {
int cnt = 0;
for(int i=1; i<MAXN; ++i) {
if(!vis[i])
++cnt;
if(cnt == n)
return i;
}
}

int main(void) {
int m, k;
while(scanf("%d%d", &m, &k) != EOF) {
if(m==1) {
printf("%d\n", k);
continue;
}
memset(vis, 0, sizeof(vis));
int ans = euler_phi(m);
int n = (k-1)%ans+1;
printf("%d\n", (k-1)/ans*m+get(n));
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: