题目
Caima 给你了所有 [a,b] 范围内的整数。一开始每个整数都属于各自的集合。每次你需要选择两个属于不同集合的整数,如果这两个整数拥有大于等于 pp 的公共质因数,那么把它们所在的集合合并。
重复如上操作,直到没有可以合并的集合为止。
现在 Caima 想知道,最后有多少个集合。
就是一道简单的并查集的问题,我写了好久,错了好多地方……
错误:
1.在判断两个数能否合并的函数中,写了一句if (pri[i]*2 > min(x, y)) break;
本来想优化,但是这样就枚举不到小正数了
以后在写优化的时候想想正确性。
2.采用n方枚举a,b 之间的两个数,能否合并,在n == 1000000 的时候会T,并且做了很多重复的合并,参考了题解,采用了枚举质数的方法,每次只合并相邻的两个倍数
3. i 和 t 写反了,以后要细心呐!
4. 使用别人正确的程序进行调试。
代码
#include <cstdio>
#include <algorithm>
#include <iostream>
using namespace std;
const int MAXN = 100010;
int a, b, p,fa[MAXN];
int find(int x)
{
if (fa[x] != x) return fa[x] = find(fa[x]);
return fa[x];
}
void unionn(int x, int y)
{
int xx = find(x); int yy = find(y);
if (xx != yy) fa[xx] = yy;
}
bool he[MAXN];
int nump, pri[MAXN];
void make_prime(int n)
{
for (int i = 2; i <= n; i ++)
{
if (!he[i]) pri[++nump] = i;
for (int j = 1; j <= nump && i * pri[j] <= n; j ++)
{
he[i*pri[j]] = 1;
if (i % pri[j] == 0) break;
}
}
}
int main()
{
scanf("%d%d%d",&a,&b,&p);
for (int i = a; i <= b; i ++)
fa[i] = i;
make_prime(b);
for (int i = 1; i <= nump; i ++)
{
if (pri[i] < p) continue;
// printf("%d ",pri[i]); cout << endl;
int t = 0;
while (pri[i] * t < a) t ++;
while (pri[i]*(t+1) <= b)
{
unionn(pri[i]*t, pri[i]*(t+1));
t ++;
}
}
int ans = 0;
for (int i = a; i <= b; i ++)
if (fa[i] == i) ans ++;
printf("%d",ans);
return 0;
}
/*
20 100000 6
10 20 3
7
365 952 5
129
*/