poj2773

题意:给出m,k,求第k小的与m互质的数。

分析:根据gcd的求法,我们可知,求最大公约数的第一步是用大数对小数取余。gcd(a,b)==gcd(a%b,b),进一步推出gcd(a,b)==gcd(a+b, b)。也就是说,当求出了1~m间与m互质的数之后,把这些数加上m就可以得到m~2m间的与m互质的数。而且m~2m间不会有某个与m互质的数被漏掉。因为如果m<=a<=2m,且gcd(a, m)==1,那么gcd(a - m, m)必然等于1。也就是必然有个在1~m间的数a-m,可以通过加m的方式得到a。所以与m互质的数是有周期性的。我们只需要求出第一个周期即可。

View Code
#include <iostream>
#include
<cstdlib>
#include
<cstring>
#include
<cstdio>
using namespace std;

#define maxn 1000005

int prm[maxn], n;
int m, k;

int kgcd(int a, int b)
{
if (a == 0)
return b;
if (b == 0)
return a;
if (!(a & 1) && !(b & 1))
return kgcd(a >> 1, b >> 1) << 1;
else if (!(b & 1))
return kgcd(a, b >> 1);
else if (!(a & 1))
return kgcd(a >> 1, b);
else
return kgcd(abs(a - b), min(a, b));
}

int main()
{
//freopen("t.txt", "r", stdin);
while (scanf("%d%d", &m, &k) != EOF)
{
if (m == 1)
{
printf(
"%d\n", k);
continue;
}
n
= 0;
for (int i = 1; i < m; i++)
if (kgcd(i, m) == 1)
prm[n
++] = i;
k
--;
printf(
"%lld\n", k / n * (long long)m + prm[k % n]);
}
return 0;
}

你可能感兴趣的:(poj)