Set 集合
【题目描述】
现在给你一些连续的整数,它们是从 A 到 B 的整数。一开始每个整数都属于各自
的集合,然后你需要进行如下操作:
每次选择两个属于不同集合的整数,如果这两个整数拥有大于等于 P 的公共质因
数,那么把它们所在的集合合并。
反复上述操作,直到没有可以合并的集合为止。
现在 Caima 想知道,最后有多少个集合。
【输入格式】
一行,三个整数 A,B,P。
【输出格式】
一个数,表示最终集合的个数。
【数据规模】
A<=B<=100000
2<=P<=B
【输入样例】
10 20 3
【输出样例】
7
【注意事项】
有 80%的数据 B<=1000。
样例解释{10,20,12,15,18},{13},{14},{16},{17},{19}。
对于两个个数,如果他们含有大于p的质因数,那么一定会被合并
我们发现集合可以按质因数分成很多,那么含有该因数的数会在这个集合
如果一个数同时含有两个因数,那么这两个区间会合并
于是就可以用并查集
可以枚举A~B,枚举质因数
假设一个数i有p1,p2,p3为质因数
把一个质因数的区间与前一个合并
这只有80分
如果枚举质因数,再枚举倍数,看一个倍数是否被其他倍数覆盖,是则合并
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #include<cmath> 6 using namespace std; 7 int A,B,P,tot,pri[100001],set[10001],cnt,st,flag,pre,num[100001]; 8 bool vis[100001]; 9 int find(int x) 10 { 11 if (set[x]!=x) set[x]=find(set[x]); 12 return set[x]; 13 } 14 int main() 15 {int i,j; 16 cin>>A>>B>>P; 17 for (i=2;i<=B;i++) 18 { 19 if (vis[i]==0) 20 { 21 tot++; 22 pri[tot]=i; 23 } 24 for (j=1;j<=tot;j++) 25 { 26 if (pri[j]*i>B) break; 27 vis[i*pri[j]]=1; 28 if (i%pri[j]==0) break; 29 } 30 } 31 memset(vis,0,sizeof(vis)); 32 for (i=1;i<=tot;i++) 33 if (pri[i]>=P) break; 34 st=i; 35 for (i=st;i<=tot;i++) 36 set[i]=i; 37 for (i=st;i<=tot;i++) 38 { 39 int a=((A-1)/pri[i]+1); 40 int b=(B/pri[i]); 41 if (a<=b) vis[i]=1; 42 for (j=a;j<=b;j++) 43 { 44 if (num[j*pri[i]]==0) num[j*pri[i]]=i; 45 else 46 { 47 int p=find(i); 48 int q=find(num[j*pri[i]]); 49 if (p!=q) 50 { 51 set[p]=q; 52 } 53 } 54 } 55 } 56 for (i=A;i<=B;i++) 57 if (num[i]==0) cnt++; 58 for (i=st;i<=tot;i++) 59 if (set[i]==i&&vis[i]==1) cnt++; 60 cout<<cnt; 61 }