好数
题目大意
U611329 好数
题目描述
如果一个正整数 \(x\) 满足 \(x = an + b (n \in \mathbb{N}^+)\)(\(a, b\) 为给定的常数),则称 \(x\) 为「好数」。
如果一个「好数」不能被除了自己以外的任何「好数」整除,则称这个数为「很好数」。
你的任务是求出前 \(m\) 个「好数」中有多少个「很好数」。
思路
看到是要将所有的好数中是很好数的个数求出来,相当于筛掉一些非很好数。所以可以用类似于质数筛的筛法来解决这个问题。
设第 \(n\) 个「好数」为「很好数」,则这个数为 \(x = an + b\)。现在需要快速的在是好数的数中筛掉非很好数即筛掉 \(x\) 的倍数。
设第 \(n'\) 好数为非很好数且为 \(x\) 倍数,设 \(an' + b = x * k\) 其中 \(k\) 为整数。
将 \(x = an + b\) 代入式子中,得 $$an' + b = (an + b) * k$$
\[an' + b = an * k + b * k
\]
\[n' = n * k + \frac{(k - 1)b}{a}
\]
设 \(d = gcd(a, b)\),则 \(a = a'd\),\(b = b'd\),且 \((a', b') = 1\),再次代入式子可以发现
\[\frac{(k-1)b'd}{a'd} = \frac{(k-1)b'}{a'}
\]
由于 \((a', b') = 1\),所以 \(a'\) 整除 \(k - 1\)。
不妨设 \(j\) 使 \(a'j = k - 1\),所以 \(k = a'j + 1\),代入原式
\[n' = n * (a'j + 1) + \frac{a'j * b'}{a'}
\]
\[n' = n * a'j + n + j * b'
\]
\[n' = j(na' + b') + n
\]
于是就可以枚举 \(j(1 \le j\ 并且\ j * (na' + b') + n \le m)\),筛掉不合法的数了。
时间复杂度 \(O(n log n)\)。
代码
#include <bits/stdc++.h>
using namespace std;
const long long N = 10000010;
long long m, a, b;
bool vis[N];
long long gcd(long long x, long long y) {
if (y == 0) return x;
return gcd(y, x % y);
}
int main() {
cin >> m >> a >> b;
long long d = gcd(a, b);
long long pa = a / d, pb = b / d, ans = 0;
for (long long i = 1; i <= m; i++)
if (!vis[i]) {
ans++;
long long x = pa * i + pb;
for (long long j = 1; j * x + i <= m; j++)
vis[j * x + i] = true;
}
cout << ans << endl;
return 0;
}

浙公网安备 33010602011771号