码迷,mamicode.com
首页 > 其他好文 > 详细

(CJOJ)P2634 - 【NOIP2017模拟】失格

时间:2017-11-08 00:01:27      阅读:247      评论:0      收藏:0      [点我收藏+]

标签:sea   i++   题目   include   for   ++   return   就是   枚举   

传送门:http://oj.changjun.com.cn/problem/detail/pid/2634

题目大意:给你n个点,每一个点都有一个权值。一条边的边权为min(Vx%Vy,Vy%Vx)。问你怎样构造一棵树,使得边权之和最小。

题解:

首先对特殊条件发掘性质:min(Vx%Vy,Vy%Vx)。不妨设Vx>Vy,那么Vy%Vx=Vy,而Vx%Vy<Vy。故边权就是Vx%Vy

然后我们想怎样连边,我们当然是要想所连的边尽量的小而不是连成一个团!所以对于权值x来说,在x~2x范围之内,当然是越小越好,那么我们就直接枚举x的倍数,然后二分查找范围内最小值即可。

这样再跑一次克鲁斯卡尔即可。

复杂度分析:

1.连边,O(n*logn*logn)

2.排序,O(n*logn*logn)

3.克鲁斯卡尔,O(n*logn*logn)

所以总复杂度还是O(n*logn*logn)。正好卡过。

 1 /*对于一个点枚举倍数,向刚刚≥倍数的连边即可,注意1倍的时候不能等于。然后克鲁斯卡尔即可。复杂度O(n*logn*logn)*/
 2 #include<cstdio>
 3 #include<iostream>
 4 #include<algorithm>
 5 using namespace std;
 6 #define RG register
 7 #define LL long long
 8 const int MAXN=1e5+7,MAXM=1e7+7;
 9 int n,Max,sz,c,Left,tp;
10 int p[MAXN],fa[MAXN],cnt[MAXM];
11 LL ans;
12 struct ed
13 {
14    int f,t,l;
15 }edge[MAXN*30];
16 bool comp(ed x,ed y) { return x.l<y.l; }
17 int find(RG int x)
18 {
19    if(x!=fa[x])fa[x]=find(fa[x]);
20    return fa[x];
21 }
22 int search(RG int v,RG int gg)
23 {
24    RG int L=1,R=sz,mid,res=R+1;
25    while(L<=R)
26       {
27          mid=(L+R)/2;
28          if(v<p[mid] || (mid!=gg&&v==p[mid]))
29             res=mid,R=mid-1;
30          else
31             L=mid+1;
32       }
33    return res;
34 }
35 int main()
36 {
37    scanf("%d",&n);
38    for(int i=1,x;i<=n;i++)
39       {
40          scanf("%d",&x);
41          cnt[x]++;
42          if(Max<x) Max=x;
43       }
44    for(int i=1;i<=Max;i++)if(cnt[i])p[++sz]=i,fa[sz]=sz;
45    Left=sz-1;
46    for(RG int i=1;i<=Max;i++)
47       if(cnt[i])
48          {
49             c++;
50             for(RG int j=i,k;j<=Max;j+=i)
51                {
52                   k=search(j,c);
53                   if(k<=sz)
54                      {
55                         edge[++tp].f=c;
56                         edge[tp].t=k;
57                         edge[tp].l=p[k]%j;
58                      }
59                }
60          }
61    sort(edge+1,edge+tp+1,comp);
62    for(RG int i=1,x,y;i<=tp;i++)
63       {
64          x=edge[i].f,y=edge[i].t;
65          if(find(x)!=find(y))
66             {
67                ans+=edge[i].l;
68                fa[find(x)]=find(y);
69                Left--;
70             }
71          if(Left<=0) break;
72       }
73    printf("%lld\n",ans);
74    return 0;
75 }

(CJOJ)P2634 - 【NOIP2017模拟】失格

标签:sea   i++   题目   include   for   ++   return   就是   枚举   

原文地址:http://www.cnblogs.com/D-O-Time/p/7801855.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!