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