题解:洛谷 P1621 集合
【题目来源】
【题目描述】
Caima 给你了所有 \([a,b]\) 范围内的整数。一开始每个整数都属于各自的集合。每次你需要选择两个属于不同集合的整数,如果这两个整数拥有大于等于 \(p\) 的公共质因数,那么把它们所在的集合合并。
重复如上操作,直到没有可以合并的集合为止。
现在 Caima 想知道,最后有多少个集合。
【输入】
一行,共三个整数 \(a,b,p\),用空格隔开。
【输出】
一个数,表示最终集合的个数。
【输入样例】
10 20 3
【输出样例】
7
【解题思路】

【算法标签】
《洛谷 1621 集合》 #搜索# #数学# #并查集# #枚举# #素数判断,质数,筛法#
【代码详解】
#include <bits/stdc++.h>
using namespace std;
const int N = 100005; // 定义最大数值范围
int p[N]; // 并查集父节点数组
int isprime[N]; // 素数标记数组
int a, b, k, ans; // a:区间起点, b:区间终点, k:最小公共质因数, ans:结果
/**
* 查找根节点(带路径压缩)
* @param x 当前节点
* @return 根节点
*/
int find(int x)
{
return p[x] == x ? x : p[x] = find(p[x]);
}
int main()
{
// 输入区间范围和最小公共质因数要求
cin >> a >> b >> k;
// 初始化并查集
for (int i = 1; i <= b; i++)
{
p[i] = i;
}
// 埃拉托斯特尼筛法标记合数
for (int i = 2; i <= b; i++)
{
if (isprime[i] == 0) // 如果是素数
{
// 标记所有i的倍数
for (int j = i + i; j <= b; j += i)
{
isprime[j] = 1; // 标记为合数
// 如果当前素数满足k的要求
if (i >= k)
{
int x = find(j);
p[x] = i; // 将j合并到i的集合
}
}
}
}
// 使用set统计不同根节点的数量
set<int> se;
for (int i = a; i <= b; i++)
{
se.insert(find(i));
}
// 输出不同集合的数量
cout << se.size();
return 0;
}
【运行结果】
10 20 3
7
浙公网安备 33010602011771号