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
题意:中文题意就不再描述。
思路:我用f(x)表示x的倍数在n个数字中出现的次数(重复的只算一次),那么设y是x的倍数, f(y)一定是小于等于f(x)的,如果有一个y是符合f(y)=f(x)那么,这个x一定不会再这个集合中出现,因为x的倍数出现了f(x)次,但是这f(x)次的出现,都是伴随着y/x这个数字的,所以x一定是不会在集合中。
举个栗子:3个数字:18 36 72,这个集合中只有这三个数字,不会有其他数字了。
f(2)=3,f(4)=2,f(6)=3,f(8)=1,f(10)=0,f(12)=2,.....f(18)=3, 只有f(x)这么多个数字求gcd能得到x,所以只用看这些数字,
2的倍数出现了三次,但是6的倍数也出现了三次,所以2一定不会在集合中,因为每次2的出现,同时也会有3跟2一块出现。
6的倍数出现了三次,但是18的倍数也出现了三次,因为每次6的出现,同时也会有3跟6一块出现,所以6也不会在集合中。
代码:
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<queue>
#include<string>
#include<algorithm>
#define inf 0x3f3f3f3f
#define LL long long
using namespace std;
int a[1001000];
int f[1001000];
int main()
{
memset(a,0,sizeof(a));
memset(f,0,sizeof(f));
int n,b,maxx=0;
scanf("%d",&n);
for(int i=0; i<n; i++)
{
scanf("%d",&b);
if(b>maxx) maxx=b;//记录一下最大值
a[b]=1;//存一下出现的数字
}
int ans=0;
for(int i=1; i<=maxx; i++)
for(int j=i; j<=maxx; j+=i)//这个地方一定要从j=i开始,要算上这个数字本身
f[i]+=a[j];//计算f[]数组
for(int i=1; i<=maxx; i++)
{
if(a[i])//这个数字出现了就直接计数
{
ans++;
continue;
}
else
{
if(f[i]<=1) continue;//这个数字的倍数出现次数小于二肯定不符合
int flag=1;
for(int j=i*2; j<=maxx; j+=i)
if(f[i]==f[j])//找他倍数中是否有跟他一样的次数的
{
flag=0;
break;
}
ans+=flag;
}
}
printf("%d\n",ans);
}