首页 > 代码库 > UVALive - 7638

UVALive - 7638

这个题有点复杂,当时有思路,就是不知道怎么写,看了大佬的代码,思考了很长时间。。。。。。这里就是先打表把每个数字的公因数存一个数组,然后以给的a[i]为大哥和他的公因数建树,再以,a[i]为小弟看有没有在树的大哥,这里想不到

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
using namespace std;
const int maxn=1000000+5;
int pre[maxn],flag[maxn],a[maxn];
int t,n,ans;
vector<int> aa[maxn];
int find(int x)
{
    if(pre[x]==x) return x;
    else return pre[x]=find(pre[x]);
}
void init()
{
    for(int i=1;i<=maxn;i++)
        pre[i]=i;
}
void unit(int x,int y)
{   x=find(x);
   y=find(y);
    if(x==y) return;
    if(x>y) pre[x]=y;
    else pre[y]=x;
}
void haha()
{
    for(int i=2;i<maxn;i++)
        for(int j=i;j<maxn;j+=i)
           aa[j].push_back(i);//把j的公因数成数组
}
int main()
{
    haha();
    scanf("%d",&t);
    for(int zz=1;zz<=t;zz++)
    {    ans=0;
       init();
        scanf("%d",&n);
        for(int i=0;i<n;i++)
        {
            scanf("%d",&a[i]);
            for(int j=0;j<aa[a[i]].size();j++)
                unit(a[i],aa[a[i]][j]);//先以a[i]为大哥,使他的小弟,也就是所有公因数指向他
        }
        memset(flag,0,sizeof(flag));
        for(int i=0;i<n;i++)
        {//再以a[i]为小弟,去寻找他的大哥
            int root=find(a[i]);//寻找出现过的a[i]的结点
            if(flag[root]==0)//没有被访问过,如果被访问过就不能加组数了
            {
                ans++;//组数增加
                if(a[i]!=1)//1很特别,反正他的节点是自己,自成一组
                    flag[root]=1;//访问过,标记
            }
        }
        printf("Case %d: %d\n",zz,ans);
    }
     return 0;
}

 

UVALive - 7638