欧拉筛先把质数整出来,现在需要一个执行将任意具有不小于p的公共质因子的整数合并.
我并没有看到什么求公共质因子的算法,而且就算有也只能想到O(N2)的合并方法.
根据欧拉筛的启示,有如下方法:
对于查找到的每一个质数pi>=p,合并pi,2pi,3pi...(直到即将越界).
之后统计集合个数即得答案.
这样操作之后可以使得任意以pi为公共质因子的整数处在同一个集合,现在只需要考虑另外一种情况,(假设各个pi形成的集合仍是相互独立的)即pi,pj两集合(设为A,B)是否合并.
当遍历合并pi的倍数时,可以肯定,如果pi*pj没有越界,此时A,B将合并,否则一定不会合并.pi*pj不越界是A,B集合合并的充分必要条件.
首先,遍历pi的倍数kpi 时,当k<pj,kpi 一定不会与pj有公因数.当k=pj,kpi 与pj一定有且仅有公因数pj.
所以这个情况已经被包含在一般处理中了.
#include <algorithm> #include <cstdio> #include <cstring> #include <iostream> #include <vector> using namespace std; bool isPrime[100010]; int a, b, p, fa[100010], ans; vector<int> s; int get(int x) { if (fa[x] == x) return x; return fa[x] = get(fa[x]); } void merge(int x, int y) { fa[get(x)] = fa[get(y)]; } void init(int n) { for (int i = 1; i <= b; i++) fa[i] = i; fill(isPrime, isPrime + 100010, 1); isPrime[1] = isPrime[0] = 0; for (int i = 2; i <= n; i++) { if (isPrime[i]) s.push_back(i); for (int j = 0; j < s.size() && i * s[j] <= n; j++) { isPrime[i * s[j]] = 0; if (i % s[j] == 0) break; } } } int main() { scanf("%d%d%d", &a, &b, &p); init(b); for (auto it = s.begin(); it != s.end(); it++) { if (*it < p) continue; for (int i = 2; i * (*it) <= b; i++) merge(*it, i * (*it)); } // 统计答案 bool used[100010] = {0}; for(int i = a; i <= b; i++) used[get(i)] = true; for(int i = a; i <= b; i++) if(used[i]) ans++; printf("%d ", ans); return 0; }