zoukankan      html  css  js  c++  java
  • P1621 集合题解

    题目传送门

    一、思路与感悟

    1、查看一下A、B集合的数据范围,发现是(1 <= a < b <= 10^5),双重循环遍历所有组合,就是(10^{10})次运算,肯定会(TLE),所以暴力是不行的。
    2、那只能是通过某些条件干掉一些数字,减小范围。题意可知,两个数都需要有一个大于等于(p)的公共质数因子,需要从这里入手。
    3、利用线筛(欧拉筛)获取到(b)范围内的所有质数。然后再通过循环,可以找到(a sim b) 之间的所有质数。
    4、利用埃筛的思想,把每一个找出来的质数,一倍一倍的增加,直到大于(b)终止,就可以找出所以符合条件的数字。
    (1)在(a sim b)之间。
    (2)有大于等于(p)的公共质数因子。

    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;
    }
    
    
  • 相关阅读:
    html JS 打开本地程序及文件
    [转]jquery mobile中redirect重定向问题
    kafka中broker、producer、consumer主要配置参数说明
    手写一个LruCache
    ES发布时max virtual memory areas vm.max_map_count [65530] is too low, increase to at least [262144] 错误
    UML类图
    JVM调优总结
    JVM学习系列(五) 常见的JVM参数
    JVM学习系列(四) 相关概念
    JVM学习系列(三) 虚拟机监控相关
  • 原文地址:https://www.cnblogs.com/littlehb/p/15111819.html
Copyright © 2011-2022 走看看