P1621 集合

题目描述

现在给你一些连续的整数,它们是从A到B的整数。一开始每个整数都属于各自的集合,然后你需要进行一下的操作:

每次选择两个属于不同集合的整数,如果这两个整数拥有大于等于P的公共质因数,那么把它们所在的集合合并。

反复如上操作,直到没有可以合并的集合为止。

现在Caima想知道,最后有多少个集合。

输入输出格式

输入格式:

 

一行,三个整数A,B,P。

【数据规模】

A≤B≤100000;

2≤P≤B。

 

输出格式:

 

一个数,表示最终集合的个数。

 

输入输出样例

输入样例#1: 
10 20 3
输出样例#1: 
7

说明

有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 }

猜你喜欢

转载自www.cnblogs.com/five20/p/9236195.html