最小集合(51nod 1616)

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
/*
  自己还是太弱了……
  因为正着考虑一定会超时,随意考虑反着做,即枚举数字,看它是否属于这个集合(其实这点我想到了)。
  检验的方法很巧妙:看这个数在原集合中出现的倍数的gcd是否等于这个数,如果相等,则该数也属于集合。
*/
#include<cstdio>
#include<iostream>
#define N 1000010
using namespace std;
int a[N],used[N],n;
int gcd(int x,int y){
    if(!y)return x;
    return gcd(y,x%y);
}
int main(){
    scanf("%d",&n);int p=0,m=0;
    for(int i=1;i<=n;i++){
        int x;scanf("%d",&x);
        if(!used[x]){
            a[++p]=x;
            used[x]=1;
            m=max(m,x);
        }
    }
    n=p;
    for(int i=1;i<=m;i++){
        if(used[i])continue;
        int w=0;
        for(int j=i;j<=m;j+=i){
            if(used[j])w=gcd(w,j);
        }
        if(w==i)p++;
    }
    printf("%d",p);
    return 0;
}

 

posted @ 2016-11-11 19:19  karles~  阅读(613)  评论(2编辑  收藏  举报