好数

题目大意

题目传送门

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;
}
posted @ 2025-10-03 12:07  wuzihenb  阅读(13)  评论(0)    收藏  举报