tzhsoj1589 set

1589: 【分区联赛模拟试题1_2.Set】

时间限制: 1 Sec  内存限制: 128 MB
提交: 2  解决: 1
[提交][状态][讨论版]

题目描述

现在给你一些连续的整数,它们是从A到B的整数。一开始每个整数都属于各自的集合,然后你需要进行一下的操作: 每次选择两个属于不同集合的整数,如果这两个整数拥有大于等于P的公共质因数,那么把它们所在的集合合并。 反复如上操作,直到没有可以合并的集合为止。 现在Caima想知道,最后有多少个集合。

输入

一行,三个整数A,B,P。 【数据规模】 A≤B≤100000; 2≤P≤B。

输出

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

样例输入

10 20 3

样例输出

7

提示

【注意事项】
有80%的数据B≤1000。
样例解释{10,20,12,15,18},{13},{14},{16},{17},{19}。

来源

首先筛一发素数。。。
然后对于每个满足要求的素数的所有倍数合并到一个集合里。。。
时间复杂度?O(n/p1 + n/p2 + n/p3 + ... + n/pk) ≤ O(nlogn)
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <map>
#include <set>
#include <vector>
#include <queue>
#include <cmath>

using namespace std;

const int N = 100010;

vector<int> prime, num[N];

int fa[N], l, r, p, vis[N], ans;

void eular(int n) {
    for(int i = 2 ; i <= n ; i ++) {
        if(!vis[i]) prime.push_back(i);
        for(int j = 0 ; j < prime.size() ; j ++) {
            if(i * prime[j] > n) break;
            vis[i * prime[j]] = 1;
            if(i % prime[j] == 0) break;
        }
    }
}

int find(int x) {
    return x == fa[x] ? x : fa[x] = find(fa[x]);
}

int main() {
    // freopen("oi.in", "r", stdin);
    scanf("%d%d%d", &l, &r, &p);
    for(int i = l ; i <= r ; i ++) {
        fa[i] = i;
    }
    eular(r);
    for(int i = 0 ; i < prime.size() ; i ++) {
        if(prime[i] < p) continue;
        int x = 0;
        while(x < l) x += prime[i];
        int u = find(x);
        while((x += prime[i]) <= r) {
            int v = find(x);
            if(u != v) {
                fa[v] = u;
            }
        }
    }
    for(int i = l; i <= r ; i ++) {
        ans += i == find(i);
    }
    printf("%d\n", ans);
}

  

posted @ 2017-09-06 17:07  KingSann  阅读(301)  评论(0编辑  收藏  举报