2021-09-13

Caima 给你了所有 [a,b][a,b] 范围内的整数。一开始每个整数都属于各自的集合。每次你需要选择两个属于不同集合的整数,如果这两个整数拥有大于等于 pp 的公共质因数,那么把它们所在的集合合并。

重复如上操作,直到没有可以合并的集合为止。

现在 Caima 想知道,最后有多少个集合。
在这里插入图片描述
在这里插入图片描述

比如整数10 和12先各自为一个集合,如果p为2,就是找到一个大于或等于2的公共质因数,显然10和22都有质因数2, 10和22就能够合并,换回来 10 和11 是否可以合并?10的因素有1 ,2, 5, 10。 11的因素有1,11,这两者没有大于2的公共质因数,10和 11就不能合并了,但是10和22是一个集合,22可以和11合并,因此10,11,22可以在一个集合内。
直观解决方法
找出【a,b】中每个数的质因数,然后与出自己外其他数一一比较,如果存在大于或等于P的公共质因数,就把两个数所在的集合合并,这里可以用并查集合并。如果两个数均在同一集合内,那么不需要合并(因为合并和不合并都一样)。这样遍历一遍之后就能得出最终的不可合并集合个数,计算集合个数得出答案。

在这里插入图片描述

例如:存在上面两个集合
怎么合并?
22在领头“10”的集合内
11本来是孤身一人,后面遇到了22,就把22拉入了队伍,“10”的集合里有22,“11”的集合里也有22,这里就可以重复了,判断22的父节点是否相等,不相等就可以合并,
在这里插入图片描述

当然也可以把左边加到右边,这里只是简单地说一下思路,还要许多补充的地方。

那么怎么找出质因数,判断两个数是否可以合并呢?按照上述方法,遍历一个数的所有质因数,在和其他数的质因数一一比较显然是不可取的,找到一个数的所有质因数要计算√n次,再次条件下又与其他数的质因数比较,那毫无理由会超时。
提一下素数筛:

就是把合数全部去除了就留下素数了。
那我们先用质数2,后面我们2,3,4把b之前的非质数排除,后面就用3,依次这样做,到4的时候已经被排除了,之后选用5,,选用6的时候在用质数2的时候已经排除了,以此类推……
就这样我们可以直接用b之前的质数进行运算。
接下来就是判断选取的质数是否大于等于p,如果满足条件,则进行集合合并。找【a,b】之间的整数是否满足合并条件。例如,我们最开始是直接选了质数2,接下来我们要2
2,2
3,2
4排除那些合数,以便找到下一个可以直接用的质数,
就有
在这里插入图片描述

prime代表质数,judge数组中存储记录哪些是可用质数
接着判断【a,b】之间可合并的数,(前面要初始化,每个数先初始化默认父亲节点是自己)
在这里插入图片描述

如果上一个符合条件的数和这个符合条件的数的跟节点不一样,就说明他们还是在两个不同的集合,就可以合并了。
注意:合并是
在这里插入图片描述

不是
在这里插入图片描述

因为i-prime所要代表的是一个集合,而这个集合可能不仅仅包含了这是这个数
在这里插入图片描述

代码如下:

#include
using namespace std;
int root[100005];
bool judge[100005];
int find(int x) {
if (root[x] == x)
return x;
else {
root[x] = find(root[x]);
return root[x];
}
}
int a, b, p, prime,i, j, sum = 0;
int main() {

cin >> a >> b >> p;
for (i = a; i <= b; i++)
	root[i] = i;
sum = b-a+ 1;
for (prime = 2; prime <= b; prime++) 
{
	if (!judge[prime]) {
		if (prime >= p) {
			for (i = prime * 2; i <= b; i += prime) {
				judge[i] = true;
				if (i - prime >= a && find(i - prime) != find(i)) {
					root[i-prime] = find(i);
					sum--;
				}


			}
		}

		else {
			for (i = prime * 2; i <= b; i += prime) {
				judge[i] = true;
			}
		}

	}
}
cout << sum;

}

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值