题意:给出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互质的数是有周期性的。我们只需要求出第一个周期即可。
![ContractedBlock.gif](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![ExpandedBlockStart.gif](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
#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;
}