题目描述 现在给你一些连续的整数,它们是从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}。
解:对于此题,我们可以想到将每个数归到它对应的质因子集合中
但是这样势必会有重复,怎么办呢?
对于每个>=p的质数,我们枚举他的倍数(假设是x)
if A<=x<=B 我们将x与p之间建一条边
到最后,如果两个点之间是有关系的,那么他们必将在图上可以互相
到达
所以最后我们只需找出最后图中有多少个联通块就可以了
1 #include<algorithm> 2 #include<iostream> 3 #include<cstring> 4 #include<string> 5 #include<vector> 6 #include<cstdio> 7 #include<cmath> 8 #define ll long 9 #define DB double 10 using namespace std; 11 const int N=1e7+10; 12 int A,B,P,p[N],ans,a[N]; 13 struct node{ 14 int u,v,ne; 15 }e[N*2]; 16 int h[N*2],tot,v[N]; 17 void add(int u,int v) 18 { 19 // cout<<u<<" "<<v<<endl; 20 tot++;e[tot]=(node){u,v,h[u]};h[u]=tot; 21 } 22 void work() 23 { 24 for(int i=2;i<=B;++i) 25 { 26 if(!v[i]) p[++p[0]]=i; 27 for(int j=1;j<=p[0] && p[j]*i<=B;++j) 28 { 29 v[p[j]*i]=1; 30 if(i%p[j]==0) break; 31 } 32 } 33 for(int i=1;i<=p[0];++i) 34 if(p[i]>=P) a[++a[0]]=p[i]; 35 for(int i=1;i<=a[0];++i) 36 { 37 int j=a[i]; 38 while(j<=B) 39 { 40 if(j>=A && j<=B) add(j,B+i),add(B+i,j); 41 j+=a[i]; 42 } 43 } 44 } 45 void dfs(int u) 46 { 47 v[u]=1; 48 for(int i=h[u];i;i=e[i].ne) 49 if(!v[e[i].v]) dfs(e[i].v); 50 } 51 int main() 52 { 53 scanf("%d%d%d",&A,&B,&P); 54 work(); 55 for(int i=A;i<=B;++i) v[i]=0; 56 for(int i=A;i<=B;++i) 57 if(!v[i]) dfs(i),ans++; 58 printf("%d",ans); 59 return 0; 60 }