范围内质数倍数集合合并——洛谷P1621

https://www.luogu.com.cn/problem/P1621  洛谷题目

其实,一开始思路想写数学的容斥,后来发现其实很难写。排除起来很麻烦。虽然省了真正的合并,但是,约数之间的计算更加繁琐。

所以,偶然想到了素筛法,能够提高对应效率。

尝试思路:1、素筛所有素数;2、将所有素数保存;3、从素数数组中找到第一个>=起点值的质数位置,从此往后尝试合并;4、继续用素筛方法合并:重点是找到第一个>=当前枚举素数的值,然后进行合并。

本题使用算法设计到了三个:素数筛法、二分查找(可以用也可以不用)、素筛和并查集一起使用的合并。

完成代码:

 1 #include <iostream>
 2 #include <cstring>
 3 #include <algorithm>
 4 
 5 using namespace std;
 6 
 7 int f[100005];
 8 int z[100000];
 9 bool s[100005];
10 
11 int getf(int x)
12 {
13     if (f[x] == x)
14         return x;
15     return f[x] = getf(f[x]);
16 }
17 
18 int main(int argc, char** argv)
19 {
20     int a, b;
21     int q;
22     int i, j;
23     int n, m;
24     int fx, fy;
25     int w;//数组起始位置 
26     cin >> a >> b >> q;
27     n = b - (a - 1);
28     memset(s, 1, sizeof(s));
29     s[0] = s[1] = m = 0;
30     for (i = 2; i * i <= 100000; i++)
31     {
32         if (s[i])
33         {
34             z[m++] = i;
35             for (j = i * i; j <= 100000; j += i)
36             {
37                 s[j] = 0;
38             }
39         }
40     }
41     for (; i <= 100000; i++)
42         if (s[i])
43             z[m++] = i;
44     for (i = 0; i <= b; i++)
45         f[i] = i;
46     /*
47     cout << m << endl;
48     for (i = 0; i < m; i++)
49         cout << z[i] << " ";
50     cout << endl;
51     */
52     //cout << n << endl;
53     w = lower_bound(z, z + m, q) - z;
54     //cout << z[w] << endl;
55     i = w;
56     while (i < m && z[i] <= b)
57     {
58         int t = a / z[i];
59         if (a % z[i] != 0)
60             t++;
61         t = t * z[i];
62         //cout << t << endl;
63         int f1 = getf(t), f2;
64         for (j = t + z[i]; j <= b; j += z[i])
65         {
66             f2 = getf(j);
67             //cout << t << " " << j << ":" << f1 << " " << f2 << endl;
68             if (f1 != f2)
69             {
70                 if (f1 > f2)
71                     swap(f1, f2);
72                 f[f2] = f1;
73                 n--;
74             }
75         } 
76         i++;
77     }
78     cout << n << endl;
79     return 0;
80 }

 

posted @ 2021-11-20 14:48  土地  阅读(82)  评论(0)    收藏  举报