51nod 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示例
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);
}





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值