51nod 1616 最小集合

来源:互联网 发布:印度 网络空间安全 编辑:程序博客网 时间:2024/06/18 18:11

1616 最小集合
基准时间限制: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示例
51 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 longusing 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);}





原创粉丝点击