zoukankan      html  css  js  c++  java
  • sdut 4408 这真的是签到题

    Problem Description

    给你n个整数,a1,a2,a3,......,an。每个整数范围1到1e6。选取任意的i(1<=i<=n)和j(1<=j<=n)如果gcd(ai,aj)>1,ai和aj为一组,如果ai和aj为一组,ai和ak为一组,那么ai,aj,ak为一组,求这n个整数中,最后有多少个组。

    Input

    输入一个T表示组数(T<=100)。然后输入一个整数n(1<=n<=1e5),最后输入n个整数ai(1<=ai<=1e6)。

    Output

    每一组测试样例输出一个整数,表示一共有多少组。

    Sample Input

    2
    3
    2 3 4
    6
    2 3 4 5 6 6

    Sample Output

    2
    2

    题解思路:

    唯一分解定理+并查集

    唯一分解定理:每一个数都可以分解为素数的乘积;

    筛一下1e6范围内的素数,将数字拆分为素数(要用sqrt()的时间);

    并查集维护关系;

    选拔赛的题目  还是好菜 自己

    #include<bits/stdc++.h>
    
    #define mem(a,b) memset(a,b,sizeof(a))
    
    using namespace std;
    
    const int maxn=1e6+80000;
    
    int prime[maxn],tot=0;
    
    bool is_prime[maxn],vis[maxn];
                        //数字数否出现
    
    int f[maxn];
    
    int root(int x)
    {
        if(x==f[x]) return f[x];
        else return f[x]=root(f[x]);
    }
    
    void make_prime()//欧拉筛
    {
        is_prime[1]=is_prime[0]=true;
        for(int i=2;i<=1e6;i++)
        {
            if(!is_prime[i])
            {
                prime[++tot]=i;
            }
            for(int j=1;j<=tot&&i*prime[j]<=1e6;j++)
            {
                is_prime[i*prime[j]]=true;
                if(i%prime[j]==0)
                {
                    break;
                }
            }
        }
    }
    
    int main(){
        make_prime();
    //    for(int i=1;i<=30;i++)
    //    {
    //        cout<<prime[i]<<endl;
    //    }
        int t;
        scanf("%d",&t);
        while(t--)
        {
            int n,now;
            mem(vis,false);
            scanf("%d",&n);
            for(int i=1;i<=n+tot;i++)
            {
                f[i]=i;
            }
            for(int i=1;i<=n;i++)
            {
                scanf("%d",&now);
                vis[i]=true;
                for(int j=1;j<=tot&&(prime[j]*prime[j]<=now);j++)//根下拆分
                {
                    if(!(now%prime[j]))
                    {
                        vis[n+j]=true;
                        int x=root(i),y=root(n+j);
                        f[x]=y;
                        while(!(now%prime[j]))
                            now/=prime[j];
                    }
                }
                if(now!=1)//如果拆到最后不是1 说明now为一个比根下now大的素数
                {
                    int x=root(i);
                    int y=n+lower_bound(prime+1,prime+1+tot,now)-prime;
                    vis[y]=true;
                    y=root(y);
                    f[x]=y;
                }
            }
            int ans=0;
    //        for(int i=1;i<=6;i++)
    //        {
    //            cout<<f[i]<<" "<<vis[i]<<endl;
    //        }
            for(int i=1;i<=n+tot;i++)
            {
                if(f[i]==i&&vis[i])
                {
                    ans++;
                }
            }
            printf("%d
    ",ans);
        }
        return 0;
    }
    
  • 相关阅读:
    MongoDB Java连接---MongoDB基础用法(四)
    MongoDB用户,角色管理 --- MongoDB基础用法(三)
    Mongodb命令 --- MongoDB基础用法(二)
    MongoDB简介---MongoDB基础用法(一)
    Docker 私有仓库
    Dockerfile
    Docker部署Mysql, Tomcat, Nginx, Redis
    Docker 容器的数据卷
    封装的多功能多效果的RecyclerView
    安卓实现沉浸式效果,状态栏变色
  • 原文地址:https://www.cnblogs.com/minun/p/10473755.html
Copyright © 2011-2022 走看看