题目描述
Caima 给你了所有 [a,b] 范围内的整数。一开始每个整数都属于各自的集合。每次你需要选择两个属于不同集合的整数,如果这两个整数拥有大于等于 p 的公共质因数,那么把它们所在的集合合并。
重复如上操作,直到没有可以合并的集合为止。
现在 Caima 想知道,最后有多少个集合。
输入格式
一行,共三个整数 a,b,p,用空格隔开。
输出格式
一个数,表示最终集合的个数。
输入输出样例
输入 #1复制
10 20 3输出 #1复制
7说明/提示
样例 1 解释
对于样例给定的数据,最后有 {10,20,12,15,18},{13},{14},{16},{17},{19},{11} 共 7 个集合,所以输出应该为 7。
数据规模与约定
- 对于 80% 的数据,1≤a≤b≤10^3。
- 对于 100% 的数据,1≤a≤b≤10^5,2≤p≤b。
代码:
#include <bits/stdc++.h>
using namespace std;
#define int long long
int a,b,p,cnt=1;
bool vis[1000010];//判断是否是质数
int pri[1000010];//记录质数
int anc[1000010];//记录每个人的祖先
int find(int c){//模板
if(anc[c]!=c) anc[c]=find(anc[c]);
return anc[c];
}
void sn(int n){//质数筛
for(int i = 2;i<=n;i++){
if(vis[i]==0) pri[cnt++]=i;//vis[i]==0代表i是质数,cnt代表质数个数-1
for(int j = 1;i*pri[j]<=n;j++){
vis[pri[j]*i]=1;//把质数的所有倍数筛掉
if(i%pri[j]==0) break;//如果i是质数的倍数,跳出循环
}
}
}
signed main(){
cin >> a >> b >> p;
sn(100010);
for(int i = a;i<=b;i++) anc[i]=i;//初始化
for(int i = 1;i<cnt;i++){
if(pri[i]<p) continue;//如果质数小于p,循环继续进行
vector<int> v;
for(int j = 1;;j++){
int x=pri[i]*j;
if(x>=a&&x<=b) v.push_back(x);//如果某个质数的倍数在[a,b],压入
if(x>b) break;
}
//v里存的是pri[i]的所有在[a,b]内的倍数,他们都拥有共同的质因子pri[i],且这个质因子>=p
for(int j = 1;j<v.size();j++){//并
int x=v[0],y=v[j];
int t1=find(x),t2=find(y);
if(t1!=t2) anc[t1]=t2;
}
}
int sum=0;
for(int i =a;i<=b;i++)
if(find(i)==i) sum++;//有多少个祖先是自己的就有多少个集合
cout << sum;
return 0;
}