题目如下
解题思路
因为K的数据很大,所以不可能去遍历到K个数
我们观察发现比m大的数其实是m+前面我们求出来的数。
所以我们只要求出比m小的数(总共cnt),答案就是 (k - 1) / cnt * m + pri[(k - 1) % cnt + 1]
while (scanf("%lld%lld", &m, &k) != EOF) {
long long cnt = 0;
for (long long i = 1; i <= m; i++) {
if (gcd(i, m) == 1) {
pri[++cnt] = i;
}
}
printf("%lld\n", (k - 1) / cnt * m + pri[(k - 1) % cnt + 1]);
}
但是如果这样直接交上去会TLE
我们观察发现每一次都要进行m次循环,才能知道比m小和m互素的数有多少(cnt),如果提前知道有多少个,那循环的时候只要找到所对应的数就可以跳出来。而知道有多少个互素的数就是我要引入的欧拉函数。
欧拉函数模板如下:
int euler_phi(int n) {
int ans = n;
for (int i = 2; i * i <= n; i++)
if (n % i == 0) {
ans = ans / i * (i - 1);
while (n % i == 0) n /= i;
}
if (n > 1) ans = ans / n * (n - 1);
return ans;
}
然后们套入模板就可以解出题目。
解题代码如下
#include <cstdio>
long long gcd(long long a, long long b) {
return (b == 0) ? a : gcd(b, a % b);
}
long long pri[1000000];
int euler_phi(int n) {
int ans = n;
for (int i = 2; i * i <= n; i++)
if (n % i == 0) {
ans = ans / i * (i - 1);
while (n % i == 0)
n /= i;
}
if (n > 1)
ans = ans / n * (n - 1);
return ans;
}
int main() {
long long m, k;
while (scanf("%lld%lld", &m, &k) != EOF) {
long long t = euler_phi(m);
long long cnt = 0;
for (long long i = 1; i <= m; i++) {
if (gcd(i, m) == 1) {
++cnt;
}
if (cnt == (k - 1) % t + 1) {
printf("%lld\n", (k - 1) / t * m + i);
break;
}
}
}
}