51nod1616 最小集合

基准时间限制:1 秒 空间限制:131072 KB 分值: 80  难度:5级算法题
 收藏
 关注

A君有一个集合。

这个集合有个神奇的性质。

若X,Y属于该集合,那么X与Y的最大公因数也属于该集合。

但是他忘了这个集合中原先有哪些数字。

不过幸运的是,他记起了其中n个数字。

当然,或许会因为过度紧张,他记起来的数字可能会重复。

他想还原原先的集合。

他知道这是不可能的……

现在他想知道的是,原先这个集合中至少存在多少数。


样例解释:

该集合中一定存在的是{1,2,3,4,6}


Input
第一行一个数n(1<=n<=100000)。
第二行n个数,ai(1<=ai<=1000000,1<=i<=n)。表示A君记起来的数字。
输入的数字可能重复。
Output
输出一行表示至少存在多少种不同的数字。
Input示例
5
1 3 4 6 6
Output示例
5

题解:

观察题目性质。
性质1:该集合中一定存在输入的数字中若干数的最大公因数。
这个证明比较简单,例如我们有a1,a2...an这些数,那么gcd(a1,a2)一定存在该集合,然后 gcd(a1,a2,a3)也一定存在该集合,依次类推。

所以我们对于每个数i,都求出在n个数中是它倍数的数,再把这些数除以i,判断它们最大公约数是否为1,如果为1,i就一定存在。如果不为1,说明这些倍数还能组成另一个数,这个数是i的倍数,但不是i,所以i不能算。


PS:我真的不懂解题报告什么意思。


代码:

#include<bits/stdc++.h>
using namespace std;
int num,k,a[2000000],ans;
int gcd(int n,int m){
	if(!m)return n;
	return gcd(m,n%m);
}
int main(){
	int n,m=0,i,j,t;
	scanf("%d",&n);
	for(i=1;i<=n;i++){
		scanf("%d",&t);
		a[t]=1;
		num=gcd(t,num);
		m=max(m,t);
	}
	if(num==1)ans=1;
	for(i=2;i<=m;i++){
		num=0;k=0;
		for(j=1;i*j<=m;j++) 
		 if(a[i*j]){
		 	num=gcd(j,num);
		 	k++;
		 }
		 if((num==1&&k>1)||a[i])ans++;
	}
	printf("%d",ans);
}


猜你喜欢

转载自blog.csdn.net/qq_41510496/article/details/80040684