upc 结队 并查集+数学

结队

时间限制: 1 Sec 内存限制: 128 MB

题目描述
众所周知,小X是一个风流倜傥、有极高人格魅力的奆老。
奆老总喜欢挑战高难度的事情,幻想着横穿和自己一样大名鼎鼎的亚马逊雨林。
这个幻想了7083年的事情终要变为现实,小X高兴得连灌两盆洗脚水。
“啊……真香……该死的甜美…………”

古代著名学者度娘在《百度百科》一书中说到:
亚马逊热带雨林(AmazonRainForest)位于南美洲的亚马逊平原,占地550万平方公里。雨林横越了9个国家:巴西(占森林60%面积)、哥伦比亚、秘鲁、委内瑞拉、厄瓜多尔、玻利维亚、圭亚那、苏里南以及法国(法属圭亚那),占据了世界雨林面积的一半,占全球森林面积的20%,是全球最大及物种最多的热带雨林。

小X万年一遇地被吓尿了。他感到面临着生命危险,需要小弟来保护,而自己的小弟实在是太少了,小X灵机一动,想到JSOI的夏令营中有很多dalao。小X照照镜子,被自己的人格魅力深深折服,信心满满。
[9102年8月8日,江苏省常州高级中学]
刚下车,小X身旁就围了一大群猛男。
“小X最帅!”
没有想到的是,小X居然被秀了。省中的dalao早已准备在这一天组成帮派。

省中的dalao从1~n进行编号。小X口味独特,只想让[a,b]区间内的dalao做自己的小弟。
dalao遵循以下规则组成帮派:
最初每个人都自成帮派。组帮派时,对于序号为m,n两个属于不同帮派的dalao,如果m,n有大于等于p的公共质因数,那么m,n所在的帮派就会合并为同一帮派。合并过后的帮派会继续合并,直至没有可以合并的帮派。
小X作为一个奆老,秉承着装弱的传统。他需要你告诉他,一共会有多少不同的帮派。

输入
一行,三个正整数A,B,P。(保证A≤B)
输出
一个正整数,表示最终的帮派个数。
样例输入 Copy
10 20 3
样例输出 Copy
7
提示
样例解释
对于[10,20]中的dalao,可分成如下帮派:
{10,20,12,15,18} {11} {13} {14} {16} {17} {19}
【数据范围】
对于30%的数据,保证有0≤A≤B≤100,P≤100
对于60%的数据,保证有0≤A≤B≤3000,P≤3000
对于100%的数据,保证有0≤A≤B≤50000,P≤50000

看到合并为一个帮派,就比较容易可以想到可以用并查集来合并。而对于如何判断是否合并的时候,可以从 b ~ k 依次枚举质因子,对于每一个质因子,提前预处理出包含这个质因子的数(唯一分解定理),让后把第一个数拿出来,让后面的数与第一个数合并即可,最后只需要找出 p[i] = i (每一个帮派的头头) 的点数量即为答案。

#include<cstdio>
#include<iostream>
#include<string>
#include<cstring>
#include<map>
#include<cmath>
#include<cctype>
#include<vector>
#include<set>
#include<queue>
#include<algorithm>
#include<sstream>
#define X first
#define Y second
using namespace std;

typedef long long LL;
typedef pair<int,int> PII;

const int N=50010,mod=1e9+7,INF=0x3f3f3f3f;
const double eps=1e-6;

int n;
int a,b,k;
int p[N];
int ans;
vector<int>v[N];

bool divide(int x)
{
	int tem=x;
	for(int i=2;i<=x/i;i++)
		if(x%i==0)
		{
			v[i].push_back(tem);
			while(x%i==0)
				x/=i;
		}
	if(x>1) 
		v[x].push_back(tem);
}

int find(int x)
{
	if(x!=p[x]) p[x]=find(p[x]);
	return p[x];
}

int main()
{
	ios::sync_with_stdio(false);
	cin.tie(0);
	
	for(int i=1;i<=50000;i++)
		p[i]=i;
	
	cin>>a>>b>>k;
	
	for(int i=a;i<=b;i++)
		divide(i);
	
	for(int i=b;i>=k;i--)
	{
		int l=v[i].size(); 
		if(l==0) continue;
		int px=find(v[i][0]);
		for(int j=1;j<l;j++)
		{
			int t=v[i][j];
			t=find(t);
			p[t]=px;
		}
	}
	
	for(int i=a;i<=b;i++)
		if(p[i]==i) ans++;
	
	cout<<ans<<endl;
















	return 0;
}










发布了46 篇原创文章 · 获赞 3 · 访问量 3240

猜你喜欢

转载自blog.csdn.net/DaNIelLAk/article/details/105643029
UPC