题目描述
现在给你一些连续的整数,它们是从A到B的整数。一开始每个整数都属于各自的集合,然后你需要进行一下的操作:
每次选择两个属于不同集合的整数,如果这两个整数拥有大于等于P的公共质因数,那么把它们所在的集合合并。
反复如上操作,直到没有可以合并的集合为止。
现在Caima想知道,最后有多少个集合。
输入输出格式
输入格式:
一行,三个整数A,B,P。
【数据规模】
A≤B≤100000;
2≤P≤B。
输出格式:
一个数,表示最终集合的个数。
输入输出样例
说明
有80%的数据B≤1000。
样例解释{10,20,12,15,18},{13},{14},{16},{17},{19},{11}。
Solution:
本题比较水。
像这种集合合并,然后统计联通块的题目,不难想到用并查集。
然后我们就直接线筛出$b$以内的素数,然后二分出不小于$p$的素数的位置,然后在$[a,b]$范围内枚举每个符合条件的质数的倍数,然后用并查集合并。
最后查询时,再维护一下树的信息,统计一下联通块个数就好了。
代码:
1 #include<bits/stdc++.h> 2 #define il inline 3 #define ll long long 4 #define For(i,a,b) for(int (i)=(a);(i)<=(b);(i)++) 5 #define Bor(i,a,b) for(int (i)=(b);(i)>=(a);(i)--) 6 #define Max(a,b) ((a)>(b)?(a):(b)) 7 #define Min(a,b) ((a)>(b)?(b):(a)) 8 using namespace std; 9 const int N=100005; 10 int prime[N+5],cnt,a,b,p,fa[N]; 11 bool isprime[N+5],vis[N]; 12 13 il int find(int x){return fa[x]==x?x:fa[x]=find(fa[x]);} 14 15 il void init(){ 16 For(i,2,b){ 17 if(!isprime[i]) prime[++cnt]=i; 18 for(int j=1;j<=cnt&&prime[j]*i<=b;j++){ 19 isprime[prime[j]*i]=1; 20 if(i%prime[j]==0)break; 21 } 22 } 23 } 24 25 int main(){ 26 ios::sync_with_stdio(0); 27 cin>>a>>b>>p; 28 For(i,a,b) fa[i]=i; 29 init(); 30 int k=lower_bound(prime+1,prime+cnt+1,p)-prime; 31 For(i,k,cnt){ 32 int l=ceil(a*1.0/prime[i]),r=b/prime[i]; 33 int x=find(fa[l*prime[i]]); 34 For(j,l+1,r) { 35 int y=find(fa[j*prime[i]]); 36 if(y!=x)fa[y]=x; 37 } 38 } 39 int tot=0; 40 For(i,a,b) { 41 fa[i]=find(fa[i]); 42 if(!vis[fa[i]]) vis[fa[i]]=1,tot++; 43 } 44 cout<<tot; 45 return 0; 46 }