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 }

 

posted @ 2017-10-30 22:17  Z-Y-Y-S  阅读(317)  评论(0编辑  收藏  举报