• [luogu p1621] 集合


    传送门

    集合

    题目描述

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

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

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

    输入输出格式

    输入格式

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

    输出格式

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

    输入输出样例

    输入样例 #1

    10 20 3
    

    输出样例 #1

    7
    

    说明

    样例 1 解释

    对于样例给定的数据,最后有 ({10,20,12,15,18},{13},{14},{16},{17},{19},{11})(7) 个集合,所以输出应该为 (7)

    数据规模与约定

    • 对于 (80\%) 的数据,(1 leq a leq b leq 10^3)
    • 对于 (100\%) 的数据,(1 leq a leq b leq 10^5,2 leq p leq b)

    分析

    这题的题目都写了大字集合了,疯狂暗示我们用并查集做啊。

    那么具体怎么做呢?

    首先我们先用欧拉筛筛出一个质数表,然后在质数表中选择 (ge p) 的质数(我们假定其为 (P)),用一个循环变量 (j) 枚举,向上乘,直到 (j imes P > b) 时停止,过程中不断将 (j imes P)(j) 合并(也就是把 (P)(j) 倍数字全部合并到一个并查集),最后(a sim b) 中有多少个集合即可,即:满足 (fa_i = i)(a le i le b) 的数有多少个。

    上代码啦。

    代码

    /*
     * @Author: crab-in-the-northeast 
     * @Date: 2020-08-19 00:27:02 
     * @Last Modified by: crab-in-the-northeast
     * @Last Modified time: 2020-08-19 01:13:48
     */
    #include <iostream>
    #include <cstdio>
    #include <cmath>
    #include <cstring>
    
    const int maxb = 100005;
    
    bool isprime[maxb];
    int prime_num[maxb];
    int fa[maxb];
    
    void prime(int n) {//预处理 1 ~ n 的所有质数
        std :: memset(isprime, true, sizeof(isprime));
        isprime[1] = false;
        for (int i = 2; i <= n; ++i) {
            if (isprime[i]) prime_num[++prime_num[0]] = i;
            for (int j = 1; j <= prime_num[0] && i * prime_num[j] <= n; ++j) {
                isprime[i * prime_num[j]] = false;
                if (i % prime_num[j] == 0) break;
            }
        }
    }
    
    int find(int x) {
        while (x != fa[x]) x = fa[x] = fa[fa[x]];
        return x;
    }
    
    int main() {
        int a, b, p;
        std :: scanf("%d%d%d", &a, &b, &p);
        prime(b);
    
        for (int i = 1; i <= b; ++i) {
            fa[i] = i;
        }
        
        for (int i = 1; i <= prime_num[0]; ++i) {
            if (prime_num[i] >= p) {
                for (int j = std :: ceil(a * 1.0 / prime_num[i]); j * prime_num[i] <= b; ++j) {
                    int fax = find(prime_num[i]);
                    int fay = find(j * prime_num[i]);
                    fa[fax] = fay;//合并所有prime_num[i] 的 j 倍数字。
                } 
            }
        }
    
        int ans = 0;
        for (int i = a; i <= b; ++i)
            if (fa[i] == i)
                ++ans;//统计集合数量
        
        std :: printf("%d
    ", ans);
        return 0;
    }
    

    评测记录

    评测记录

  • 相关阅读:
    QAction使用
    QT学后感
    设置背景图片
    获取句柄的方法总结(尤其是对于dll而言)
    unixbench小试
    Java命令行之jar命令
    Java应用程序安装包制作工具简介
    Eclipse使用ant编译时的乱码问题
    Jboss4中使用配置发送邮件
    Exe4j注册码
  • 原文地址:https://www.cnblogs.com/crab-in-the-northeast/p/luogu-p1621.html
Copyright © 2020-2023  润新知