• 10.02T5 枚举因数+纵向思考


    Description

    Input

      输入文件为二行,第一行为N,第二行为N个数Ai。

    Output

    一个数即答案

    Sample Input

    5 5 6 7 10 21

    Sample Output

    17

    Hint


    【数据规模与约定】
     
     
     
     
     
    题解:
    首先最暴力的做法肯定就是枚举n^2条边然后进行排序,接着我们再用kruskal求一遍最大生成树就可以了
    然后我们看部分数据怎么处理,首先我们知道如果ai是有重复的话实际上就是一样的,首先可以去重在剩下的数字里面进行暴力
    接下来我们考虑一个问题,如果一条边的权值是 i 那么它一定是由k1*i,k2*i 的点之间的。
    显然按照题目的数据范围我们可以暴力统计每一个数字的所有因数,然后考虑在尽量大的相同的因子的两个数之间连边
    所以这里我们可以使用vector进行统计,vector i 存储的是因数有 i 的全部数字的编号,然后跑kruskal的时候我们可以从大到小枚举这个 i 的编号连边,用并查集维护一下,输出答案就可以了
    code:
     1 #include<iostream>
     2 #include<cstdio>
     3 #include<vector>
     4 using namespace std;
     5 vector<int>fac[100000];
     6 int max0,fa[100005],n,a[100005];
     7 int read(){
     8     int f=1,x=0;
     9     char c=getchar();
    10     while(!isdigit(c)){
    11         if(c=='-')f=-1;
    12         c=getchar();
    13     }
    14     while(isdigit(c)){
    15         x=(x<<3)+(x<<1)+c-'0';
    16         c=getchar();
    17     }
    18     return x*f;
    19 }
    20 
    21 int find(int x){
    22     if(x!=fa[x])return fa[x]=find(fa[x]);
    23     return fa[x];
    24 }
    25 void merge(int x,int y){
    26     int f1=find(x),f2=find(y);
    27     if(f1!=f2){
    28         fa[f1]=f2;
    29     }
    30 }
    31 void kruskal(){
    32     long long ans=0;
    33     int cnt=0;
    34     for(int i=max0;i>=1;i--){
    35         for(int j=1;j<fac[i].size();j++){
    36             int x=fac[i][j],y=fac[i][j-1];
    37             if(find(x)!=find(y)){
    38                 merge(x,y);
    39                 ans+=i;
    40                 if(cnt==n-1){
    41                     cout<<ans;
    42                     exit(0);
    43                 }    
    44             }
    45         }
    46     }
    47     cout<<ans;
    48 }
    49 int main(){
    50     n=read();
    51     for(int i=1;i<=n;i++){
    52         a[i]=read();
    53         fa[i]=i;
    54         max0=max(max0,a[i]);
    55     }
    56     for(int i=1;i<=n;i++){
    57         for(int j=1;j*j<=a[i];j++){//暴力分解每一个数字的因子 
    58             if(a[i]%j==0){//如果可以整除就代表可以组成gcd 
    59                 fac[j].push_back(i);//那么这个数字的倍数里面就会有这个数字 
    60                 fac[a[i]/j].push_back(i);//同样这个数字因子被除了之后的里面也会有这个数字 
    61             }
    62         }
    63     }
    64     kruskal();
    65 }

    over

  • 相关阅读:
    sql函数 StringSplit(SELECT * from Split('黄色,蓝色,黑色',','))
    跨表循环写插入sql语句
    将ExCel导入数据库
    行转列
    js正则匹配
    ASP.NET下载远程图片保存到本地的方法、保存抓取远程图片
    C# 解析json类型字符串
    上传图片
    存储过程学习
    //js验证数字输入,以及保留俩位
  • 原文地址:https://www.cnblogs.com/saionjisekai/p/9762922.html
Copyright © 2020-2023  润新知