P1621 集合

传送门

解题思路

因为是在[a,b]范围内将两个拥有大于等于P的公共质因数的整数进行合并,关于质数的操作我们很容易会联想到素数筛,实际上就是这样,我们先通过欧拉筛,然后我们找到第一个大于等于a的质数,然后将[a,b]范围内的该质数的倍数进行合并操作,最后从a到b数一下有多少个分类即可

Code

#include<bits/stdc++.h>
using namespace std;
#define endl "\n"

const int N = 100005;

int primes[N];
bool vis[N];
int b,a,p;
int fa[N];


void init() {
	for(int i = 1;i < N; ++i) fa[i] = i;
}

void get_prime(int n) {
	vis[0] = vis[1] = true;
	for(int i = 2;i <= n; ++i) {
		if(!vis[i]) 
			primes[++primes[0]] = i;
		for(int j = 1;j <= primes[0] && primes[j] * i <= n; ++j) {
			vis[primes[j] * i] = true;
			if(i % primes[j] == 0) break;
		}
	}
}


int find(int x) {
	int t = x;
	while(t != fa[t]) {
		t = fa[t];
	}
	while(x != fa[x]) {
		int temp = fa[x];
		fa[x] = t;
		x = temp;
	}
	return x;
}

void merge(int l,int r) {
	l = find(l);
	r = find(r);
	if(l != r) {
		fa[r] = l;
	}
}

int main()
{
	scanf("%d%d%d",&a,&b,&p);
	init();
	get_prime(b);
	int i = lower_bound(primes+1,primes+1+primes[0],p) - primes;
//	while(primes[i] < a) i++;
	for(;i < primes[0] && primes[i] <= b; ++i) {
		int k = primes[i];
		for(int j = 1;j <= b && j * k <= b; ++j) {
				merge(k,j * k);
		}
	}
	set<int> ans;
	for(i = a; i <= b; ++i) {
//		printf("i = %d  find() = %d\n",i,find(i));
		ans.insert(find(i));
	}
	printf("%d\n",ans.size());
	return 0;
}
/*
10 20 3
*/ 
posted @ 2021-05-04 11:05  MangataTS  阅读(70)  评论(0编辑  收藏  举报