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);
}