集合

题目描述
现在给你一些连续的整数,它们是从A到B的整数。一开始每个整数都属于各自的集合,然后你需要进行一下的操作:
每次选择两个属于不同集合的整数,如果这两个整数拥有大于等于P的公共质因数,那么把它们所在的集合合并。
反复如上操作,直到没有可以合并的集合为止。
现在Caima想知道,最后有多少个集合。
输入输出格式
输入格式:
一行,三个整数A,B,P。
【数据规模】
A≤B≤1000002≤P≤B。
输出格式:
一个数,表示最终集合的个数。
输入输出样例
输入样例#110 20 3
输出样例#17
说明
有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 } 
代码

 

posted @ 2018-04-11 16:08  月亮茶  阅读(200)  评论(0编辑  收藏  举报