【链表】bzoj 1150: [CTSC2007]数据备份Backup

1150: [CTSC2007]数据备份Backup

Time Limit: 10 Sec  Memory Limit: 162 MB
Submit: 1136  Solved: 458
[Submit][Status][Discuss]

Description

Input

输入的第一行包含整数n和k,其中n(2 ≤ n ≤100 000)表示办公楼的数目,k(1≤ k≤ n/2)表示可利用的网络电缆的数目。接下来的n行每行仅包含一个整数(0≤ s ≤1000 000 000), 表示每个办公楼到大街起点处的距离。这些整数将按照从小到大的顺序依次出现。

Output

输出应由一个正整数组成,给出将2K个相异的办公楼连成k对所需的网络电缆的最小总长度。

Sample Input

5 2
1
3
4
6
12

Sample Output

4

HINT

上面的样例输入给出了前面描述的示例情形 对于每一个测试点,如果写到输出文件中的答案正确,则得到该测试点100%的分数,否则得零分。30%的输入数据满足n≤20。60%的输入数据满足n≤10 000。


  一开始觉得要贪心什么的

  瞄了一眼题解

  貌似我再想一下能出来( 大雾

  然后感觉好困。。

  最后几乎是半抄完了

  易得每次只能选相邻点

  所有只有n-1条边可选

  每次链表选最小的

  然后选完后合并前一个和后一个

  具体来说就是堆维护最小值

  每次合并-->该边和上一条和下一条不可选,创建一个新的节点代替原来的三个,ans加上权值

  权值是左边+右边-中间(再选新节点=不选中间选两边)

  还有就是选队首队尾,则易得选队首的后一个和选队尾的前一个不可能优。

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 #include<cmath>
 5 #include<queue>
 6
 7 #define maxn 1000001
 8
 9 using namespace std;
10
11 int a[maxn*2],n,k,pre[maxn*2],next[maxn*2],num=0;
12
13 long long cha[maxn*2],ans=0;
14
15 bool vis[maxn*2];
16
17 struct node{
18     int x;
19     long long c;
20     bool operator <(const node &A)const{
21         if(A.c==c)return x>A.x;
22         return c>A.c;
23     }
24 };
25
26 priority_queue<node>q;
27
28 inline int in()
29 {
30     int x=0;char ch=getchar();
31     while(ch<‘0‘||ch>‘9‘)ch=getchar();
32     while(ch>=‘0‘&&ch<=‘9‘)x=x*10+ch-‘0‘,ch=getchar();
33     return x;
34 }
35
36 void Pre()
37 {
38     for(int i=1;i<n;i++)
39         cha[i]=a[i+1]-a[i],q.push((node){i,a[i+1]-a[i]}),pre[i]=i-1,next[i]=i+1;
40     num=n;
41     pre[n]=n-1;next[0]=1;
42 }
43
44 void solve()
45 {
46     node Top;
47     for(int i=1;i<=k;i++)
48     {
49         Top=q.top();q.pop();
50         while(vis[Top.x])
51             Top=q.top(),q.pop();
52         if(pre[Top.x]==0)
53         {
54             pre[next[next[Top.x]]]=0;
55             ans+=Top.c;
56             vis[Top.x]=vis[next[Top.x]]=1;
57         }
58         else if(next[Top.x]==n)
59         {
60             next[pre[pre[Top.x]]]=n;
61             ans+=Top.c;
62             vis[Top.x]=vis[pre[Top.x]]=1;
63         }
64         else
65         {
66             ans+=Top.c;
67             node New;
68             New.x=++num;
69             New.c=cha[pre[Top.x]]+cha[next[Top.x]]-Top.c;
70             pre[New.x]=pre[pre[Top.x]],next[pre[New.x]]=New.x;
71             next[New.x]=next[next[Top.x]],pre[next[New.x]]=New.x;
72             vis[Top.x]=vis[next[Top.x]]=vis[pre[Top.x]]=1;
73             cha[num]=New.c;
74             q.push(New);
75         }
76     }
77 }
78
79 int main()
80 {
81     n=in();k=in();
82     for(int i=1;i<=n;i++)a[i]=in();
83     Pre();solve();
84     printf("%lld",ans);
85     return 0;
86 }

时间: 2024-08-05 07:06:40

【链表】bzoj 1150: [CTSC2007]数据备份Backup的相关文章

bzoj 1150: [CTSC2007]数据备份Backup

Description 你在一家 IT 公司为大型写字楼或办公楼(offices)的计算机数据做备份.然而数据备份的工作是枯燥乏味 的,因此你想设计一个系统让不同的办公楼彼此之间互相备份,而你则坐在家中尽享计算机游戏的乐趣.已知办公 楼都位于同一条街上.你决定给这些办公楼配对(两个一组).每一对办公楼可以通过在这两个建筑物之间铺设网 络电缆使得它们可以互相备份.然而,网络电缆的费用很高.当地电信公司仅能为你提供 K 条网络电缆,这意味 着你仅能为 K 对办公楼(或总计2K个办公楼)安排备份.任一

bzoj 1150: [CTSC2007]数据备份Backup【链表+堆】

参考:http://blog.csdn.net/Regina8023/article/details/44158947 神奇的做法.题意相当于若干个数取不相邻的k个使最小.先把数组差分,len表示这段空的长度.设二元组(i,len[i]),开一个小根堆把二元组塞进去,以len排序.每次取出一个二元组,因为单纯的贪心是不行的,所以设计一个"反悔"操作.记录二元组的前驱pr后继ne,把拿出来的二元组的len加进答案,然后把当前二元组和它的前驱后继当成一个,也就是len[x]=len[pr[

BZOJ 1150 [CTSC2007]数据备份Backup(贪心+优先队列)

[题目链接] http://www.lydsy.com/JudgeOnline/problem.php?id=1150 [题目大意] 给出n个数,请你挑出k对(每个数不可重复选取),使得他们差的绝对值之和最小(k小于等于n/2) [题解] 因为数列给出有序,省去排序步骤,我们发现最优答案一定是选择k对相邻的数, 因此我们将相邻的数两两之间求差,得到差分数列, 现在问题转化为在这个新的数列中,选取k个不相邻的数,使得和最小. 我们发现在选取一个数之后,只对左右两边的数有影响, 所以,每当我们选取一

BZOJ 1150 CTSC2007 数据备份Backup 堆+贪心

题目大意:给定一个长度为n?1的序列,要求选出k个不相邻的数使得和最小 费用流显然能跑,而且显然过不去- - 考虑用堆模拟费用流 一个错误的贪心是每次取最小,这样显然过不去样例 我们把[每次取最小]改为[每次选择一个区间取反],用堆来维护这些区间即可 每次取出最小的区间,然后将两边合并 (比如现在堆里有[1,3][4,4][5,5])这三个区间,我取走了[4,4]并计入答案,那么我删除[1,3]和[5,5]这两个区间,并加入[1,5]这个区间,权值为[1,3]的权值+[5,5]的权值-[4,4]

【BZOJ 1150】 1150: [CTSC2007]数据备份Backup (贪心+优先队列)

1150: [CTSC2007]数据备份Backup Description 你在一家 IT 公司为大型写字楼或办公楼(offices)的计算机数据做备份.然而数据备份的工作是枯燥乏味 的,因此你想设计一个系统让不同的办公楼彼此之间互相备份,而你则坐在家中尽享计算机游戏的乐趣.已知办公 楼都位于同一条街上.你决定给这些办公楼配对(两个一组).每一对办公楼可以通过在这两个建筑物之间铺设网 络电缆使得它们可以互相备份.然而,网络电缆的费用很高.当地电信公司仅能为你提供 K 条网络电缆,这意味 着你仅

1150: [CTSC2007]数据备份Backup

1150: [CTSC2007]数据备份Backup https://lydsy.com/JudgeOnline/problem.php?id=1150 分析: 堆+贪心. 每次选最小的并一定是最优的,如果不选这个最小的,那一定是为了取它左右两边(两条都要取才可能比当前优). 如果先选了最小的,考虑后面如何撤销.选了这个后,左右两边的线段就要删了,那么在加入一个长度为:左边的长度+右边的长度-当前的线段的长度 的一条线段. wqs二分,模拟费用流 代码: 1 #include<cstdio>

【bzoj1150】[CTSC2007]数据备份Backup 模拟费用流+链表+堆

题目描述 你在一家 IT 公司为大型写字楼或办公楼(offices)的计算机数据做备份.然而数据备份的工作是枯燥乏味的,因此你想设计一个系统让不同的办公楼彼此之间互相备份,而你则坐在家中尽享计算机游戏的乐趣.已知办公楼都位于同一条街上.你决定给这些办公楼配对(两个一组).每一对办公楼可以通过在这两个建筑物之间铺设网络电缆使得它们可以互相备份.然而,网络电缆的费用很高.当地电信公司仅能为你提供 K 条网络电缆,这意味着你仅能为 K 对办公楼(或总计2K个办公楼)安排备份.任一个办公楼都属于唯一的配

BZOJ1150 [CTSC2007]数据备份Backup 【堆 + 链表】

题目 你在一家 IT 公司为大型写字楼或办公楼(offices)的计算机数据做备份.然而数据备份的工作是枯燥乏味 的,因此你想设计一个系统让不同的办公楼彼此之间互相备份,而你则坐在家中尽享计算机游戏的乐趣.已知办公 楼都位于同一条街上.你决定给这些办公楼配对(两个一组).每一对办公楼可以通过在这两个建筑物之间铺设网 络电缆使得它们可以互相备份.然而,网络电缆的费用很高.当地电信公司仅能为你提供 K 条网络电缆,这意味 着你仅能为 K 对办公楼(或总计2K个办公楼)安排备份.任一个办公楼都属于唯一

BZOJ1150 [CTSC2007]数据备份Backup

这是一道很好的题目,正常人都想不出做法. 我还记得题解是说: (1)想到动规,但是T到死... (2)转化成网络流,还是T的不行 (3)咦,好像是贪心欸,做出来了(你在卖萌!) 其实算法很简单,首先我们知道必须找相邻的两个进行配对,但是不是直接找最小,而是每次要找最短的一段(后面会解释什么叫"段"),于是可以用堆来维护. 具体做法是找出当前最短的段X,设左边那段叫L,右边那段叫R,那么: 只要(1)ans += dis[X]  (2)删除X.L.R三段,即堆中删除dis[X], dis