F - Number of Connected Components UVALive - 7638 (并查集 + 思维)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/Let_life_stop/article/details/85059511

题目链接:https://cn.vjudge.net/contest/275589#problem/F

题目大意:就是给你n个数,如果说两个数之间的gcd!=1,那么就将这两个点连起来,问你最终这些点能形成几块

具体思路:首先,我们可以讲所有数的倍数给标记出来,然后如果有一个数是 6,我们就把2 3 6 全部指向6,这样的话,每当我们找到一个数,我们就把这个数和他的素因子连起来(并查集),往小的地方连,然后最后看一下输入的n个数是不是标记的自己,如果是自己那么这肯定是一个块,如果不是标记的自己,就证明他所在的块已经被算过了(这也太暴力了...)

AC代码:

#include<bits/stdc++.h>
using namespace std;
# define inf 0x3f3f3f3f
# define ll long long
const int maxn = 1000000+100;
int a[maxn],vis[maxn],father[maxn];
vector<int>q[maxn];
void init()
{
    for(int i=2; i<=maxn; i++)
    {
        for(int j=i*2; j<=maxn; j+=i)
        {
            q[j].push_back(i);
        }
    }
}
int Find(int t)
{
    return t==father[t]?t:father[t]=Find(father[t]);
}
void cal(int t1,int t2)
{
    int x1=Find(t1);
    int y1=Find(t2);
    if(x1!=y1)
    {
        if(x1>y1)father[x1]=y1;
        else father[y1]=x1;
    }
}
int main()
{
    init();
    int T;
    scanf("%d",&T);
    int Case=0;
    while(T--)
    {
        int n;
        scanf("%d",&n);
        for(int i=1; i<=maxn; i++)
        {
            father[i]=i;
        }
        memset(vis,0,sizeof(vis));
        for(int i=1; i<=n; i++)
        {
            scanf("%d",&a[i]);
            int len=q[a[i]].size();
            for(int j=0; j<len; j++)
            {
                cal(a[i],q[a[i]][j]);
            }
        }
        ll ans=0;
        for(int i=1; i<=n; i++)
        {
            if(a[i]==1)
            {
                ans++;
                continue;
            }
            int t=Find(a[i]);
            if(vis[t])continue;
            vis[t]=1;
            ans++;
        }
        printf("Case %d: %lld\n",++Case,ans);
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/Let_life_stop/article/details/85059511