题解:洛谷 P1621 集合

【题目来源】

洛谷:P1621 集合 - 洛谷

【题目描述】

Caima 给你了所有 \([a,b]\) 范围内的整数。一开始每个整数都属于各自的集合。每次你需要选择两个属于不同集合的整数,如果这两个整数拥有大于等于 \(p\) 的公共质因数,那么把它们所在的集合合并。

重复如上操作,直到没有可以合并的集合为止。

现在 Caima 想知道,最后有多少个集合。

【输入】

一行,共三个整数 \(a,b,p\),用空格隔开。

【输出】

一个数,表示最终集合的个数。

【输入样例】

10 20 3

【输出样例】

7

【解题思路】

image

【算法标签】

《洛谷 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
posted @ 2026-02-18 14:23  团爸讲算法  阅读(0)  评论(0)    收藏  举报