P1621 集合题解
一、思路与感悟
1、查看一下A、B集合的数据范围,发现是,双重循环遍历所有组合,就是次运算,肯定会,所以暴力是不行的。
2、那只能是通过某些条件干掉一些数字,减小范围。题意可知,两个数都需要有一个大于等于的公共质数因子,需要从这里入手。
3、利用线筛(欧拉筛)获取到范围内的所有质数。然后再通过循环,可以找到 之间的所有质数。
4、利用埃筛的思想,把每一个找出来的质数,一倍一倍的增加,直到大于终止,就可以找出所以符合条件的数字。
(1)在之间。
(2)有大于等于的公共质数因子。
5、把这些数字存储到一个变长数组中,将这个变长数组中的每一个符合条件的数字合并并查集。
6、找出最后并查集的个数,输出。
二、难点与知识点总结
1、线性筛(欧拉筛)
2、埃筛思想,找出区间内某个数字的整数倍。
3、并查集模板
4、计算并查集的个数。
三、C++代码
#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 10;
/**
测试用例:
10 20 3
答案:
7
*/
//欧拉筛
int primes[N], cnt; // primes[]存储所有素数
bool st[N]; // st[x]存储x是否被筛掉
void get_primes(int n) {
for (int i = 2; i <= n; i++) {
if (!st[i]) primes[cnt++] = i;
for (int j = 0; primes[j]*i <= n; j++) {
st[primes[j] * i] = true;
if (i % primes[j] == 0) break;
}
}
}
//并查集数组
int fa[N];
//要深入理解这个递归并压缩的过程
int find(int x) {
if (fa[x] != x) fa[x] = find(fa[x]);
return fa[x];
}
//加入家族集合中
void join(int c1, int c2) {
int f1 = find(c1), f2 = find(c2);
if (f1 != f2)fa[f1] = f2;
}
//读入一个开始和结束,a:开始,b:结束
int a, b, p, ans;
int main() {
//读入
cin >> a >> b >> p;
//并查集初始化
for (int i = a; i <= b; i++) fa[i] = i;
//筛出b以内的所有素数
get_primes(b);
//遍历筛出的质数表,找到每一个大于等于p的质数,然后把这个质数在y范围内的倍数找出来,并加入到动态数组v中
for (int i = 0; i < cnt; i++) {
if (primes[i] >= p) {
//将具有公共质数因子的数,放到一个数组v中
vector<int> v;
for (int j = 1; j * primes[i] <= b; j++)//找出质数倍数
if (j * primes[i] >= a && j * primes[i] <= b)
v.push_back(j * primes[i]);
//把数组v中的元素进行并查集关联
for (int j = 1; j < v.size(); j++)
join(v[j - 1], v[j]);
}
}
//并查集个数
for (int i = a; i <= b; i++) if (fa[i] == i) ans++;
//输出
cout << ans << endl;
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· Docker 太简单,K8s 太复杂?w7panel 让容器管理更轻松!
2015-08-07 通过测试想到的一些问题