官方题解|数的集合
2025-02-04 22:10:23
发布于:北京
54阅读
0回复
0点赞
题目解析
本题有两种方法可以解决,前者的切入点更平滑,后者更偏向于数学直觉一些。
方法一(并查集)
比较直接的一个想法,从 开始执行搜索,把 中未加入集合且与当前元素不互质的元素加入集合 。
那么显然我们的目标就是如何快速地找到与 不互质的元素集合 ,对于 中的每个元素,再找到与其不互质的元素,以此类推。
由于本题中的操作具有传递性质: 与 不互质; 与 不互质,那么 ,, 都属于同一个集合。
我们可以从小到大考虑每个元素 ,令 的最小质因子 ,那么有:
- 若 为质数,显然集合中只有 本身。
- 若 不为质数,那么显然我们将其拆分为 与 ,那么二者所在的集合可以借助 合并起来。
我们将处理到元素 时,其所在的集合的大小设为 ,那么对应的操作次数为 。
所以我们可以预处理 中的所有元素,然后依次回答每个查询即可。
令 ,此方法时间复杂度为 。
并查集每个操作平均时间复杂度为 ,其中 为阿克曼函数的反函数,其增长极其缓慢,也就是说其单次操作的平均运行时间可以认为是一个很小的常数。
方法二(前缀和)
如果仔细分析最终集合 中的元素会发现,在当 不为素数时,所有素数 都是无法加入到集合中的。其原因从上面的并查集解中不难发现,对于这样元素 是无法通过拆解 来使其合并到 所在的集合的。
我们令 表示前 个元素中素数的数量,那么对于每个 ,若 为素数,操作次数为 ,否则为 。
那么我们在做完筛法后,使用前缀和计算出所有的 即可。
令 ,此方法时间复杂度为 。
AC代码
方法一(并查集)
#include <bits/stdc++.h>
class UnionFind {
private:
int n;
std::vector<int> dsu;
public:
UnionFind(int n = 0) : n(n), dsu(n, -1) {}
int find(int x) {
if (dsu[x] < 0) return x;
return dsu[x] = find(dsu[x]);
}
int unite(int x, int y) {
x = find(x), y = find(y);
if (x == y) return x;
if (dsu[x] > dsu[y]) std::swap(x, y);
dsu[x] += dsu[y];
dsu[y] = x;
return x;
}
bool same(int x, int y) {
return find(x) == find(y);
}
int size(int x) {
return -dsu[find(x)];
}
};
constexpr int N = 3e6;
int main() {
std::cin.tie(nullptr)->sync_with_stdio(false);
int st[N + 1]{};
for (int i = 2; i * i <= N; ++i) {
if (st[i]) continue;
for (int j = i * i; j <= N; j += i)
st[j] = i;
}
UnionFind d(N + 1);
int res[N + 1]{};
for (int i = 2; i <= N; ++i) {
if (st[i]) {
d.unite(i, st[i]);
d.unite(i, i / st[i]);
}
res[i] = d.size(i) - 1;
}
int q; std::cin >> q;
while (q--) {
int n; std::cin >> n;
std::cout << res[n] << '\n';
}
return 0;
}
方法二(前缀和)
#include <bits/stdc++.h>
constexpr int N = 3e6;
std::bitset<N + 1> st;
int cnt[N + 1];
auto init = []() {
for (int i = 2; i * i <= N; ++i) {
if (st[i]) continue;
for (int j = i * i; j <= N; j += i)
st[j] = 1;
}
for (int i = 2; i <= N; ++i)
cnt[i] = cnt[i - 1] + !st[i];
return 0;
} ();
int solve() {
int n; std::cin >> n;
if (!st[n])
std::cout << 0 << '\n';
else
std::cout << n - (cnt[n] - cnt[n / 2]) - 2 << '\n';
return 0;
}
int main() {
std::cin.tie(nullptr)->sync_with_stdio(false);
int _; std::cin >> _;
while (_--) solve();
return 0;
}
这里空空如也
有帮助,赞一个