(CJOJ)P2634 - NOIP2017模拟失格

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了(CJOJ)P2634 - NOIP2017模拟失格相关的知识,希望对你有一定的参考价值。

传送门: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模拟失格的主要内容,如果未能解决你的问题,请参考以下文章

2017.11.25NOIP提高组模拟赛A组

2017.12.09NOIP提高组模拟赛A组

2017.5.27 NOIP模拟赛(hzwer2014-5-16 NOIP模拟赛)

2017-9-26 NOIP模拟赛

2017.12.02NOIP提高组模拟赛A组

2017.11.7~8模拟测试总结---暨NOIP2017考前对策