1150: [CTSC2007]数据备份Backup
Submit: 2899 Solved: 1172
[Submit][Status][Discuss]
Description
你在一家 IT 公司为大型写字楼或办公楼(offices)的计算机数据做备份。然而数据备份的工作是枯燥乏味
的,因此你想设计一个系统让不同的办公楼彼此之间互相备份,而你则坐在家中尽享计算机游戏的乐趣。已知办公
楼都位于同一条街上。你决定给这些办公楼配对(两个一组)。每一对办公楼可以通过在这两个建筑物之间铺设网
络电缆使得它们可以互相备份。然而,网络电缆的费用很高。当地电信公司仅能为你提供 K 条网络电缆,这意味
着你仅能为 K 对办公楼(或总计2K个办公楼)安排备份。任一个办公楼都属于唯一的配对组(换句话说,这 2K
个办公楼一定是相异的)。此外,电信公司需按网络电缆的长度(公里数)收费。因而,你需要选择这 K 对办公
楼使得电缆的总长度尽可能短。换句话说,你需要选择这 K 对办公楼,使得每一对办公楼之间的距离之和(总距
离)尽可能小。下面给出一个示例,假定你有 5 个客户,其办公楼都在一条街上,如下图所示。这 5 个办公楼分
别位于距离大街起点 1km, 3km, 4km, 6km 和 12km 处。电信公司仅为你提供 K=2 条电缆。
![](https://www.lydsy.com/JudgeOnline/upload/201604/1111.png)
上例中最好的配对方案是将第 1 个和第 2 个办公楼相连,第 3 个和第 4 个办公楼相连。这样可按要求使用
K=2 条电缆。第 1 条电缆的长度是 3km-1km=2km ,第 2 条电缆的长度是 6km-4km=2km。这种配对方案需要总长
4km 的网络电缆,满足距离之和最小的要求。
Input
第一行包含整数n和k
其中n(2≤n≤100000)表示办公楼的数目,k(1≤k≤n/2)表示可利用的网络电缆的数目。
接下来的n行每行仅包含一个整数(0≤s≤1000000000),表示每个办公楼到大街起点处的距离。
这些整数将按照从小到大的顺序依次出现。
Output
输出应由一个正整数组成,给出将2K个相异的办公楼连成k对所需的网络电缆的最小总长度。
Sample Input
5 2
1
3
4
6
12
1
3
4
6
12
Sample Output
4
思路:首先证明不取全局最小值时一定是把它相邻的两个取了。然后每次取最小值后,向堆中加入v[p -> pre] + v[p -> nex] - v[p],这样如果之后取了这个元素,则等价于取了与p相邻的两个,并把之前取的p悔掉。
实现时用个堆与链表构成对应关系即可,第一次写得推敲一会。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include <iostream> 2 #include <fstream> 3 #include <sstream> 4 #include <cstdlib> 5 #include <cstdio> 6 #include <cmath> 7 #include <string> 8 #include <cstring> 9 #include <algorithm> 10 #include <queue> 11 #include <stack> 12 #include <vector> 13 #include <set> 14 #include <map> 15 #include <list> 16 #include <iomanip> 17 #include <cctype> 18 #include <cassert> 19 #include <bitset> 20 #include <ctime> 21 22 using namespace std; 23 24 #define pau system("pause") 25 #define ll long long 26 #define pii pair<int, int> 27 #define pb push_back 28 #define mp make_pair 29 #define clr(a, x) memset(a, x, sizeof(a)) 30 31 const double pi = acos(-1.0); 32 const int INF = 0x3f3f3f3f; 33 const int MOD = 1e9 + 7; 34 const double EPS = 1e-9; 35 36 /* 37 #include <ext/pb_ds/assoc_container.hpp> 38 #include <ext/pb_ds/tree_policy.hpp> 39 40 using namespace __gnu_pbds; 41 tree<pli, null_type, greater<pli>, rb_tree_tag, tree_order_statistics_node_update> T; 42 */ 43 44 int n, k, d[100015]; 45 struct gg { 46 int l, r, v, use, index; 47 gg () {} 48 gg (int l, int r, int v, int use, int index) : l(l), r(r), v(v), use(use), index(index) {} 49 bool operator > (const gg &g) const { 50 return v > g.v; 51 } 52 } g[200015]; 53 priority_queue<gg, vector<gg>, greater<gg> > que; 54 int main() { 55 scanf("%d%d", &n, &k); 56 d[0] = -MOD, d[n + 1] = MOD << 1; 57 for (int i = 1; i <= n; ++i) { 58 scanf("%d", &d[i]); 59 g[i].l = i - 1; 60 g[i].r = i + 1; 61 g[i].v = d[i] - d[i - 1]; 62 g[i].use = 0; 63 g[i].index = i; 64 que.push(g[i]); 65 } 66 g[n + 1].l = n, g[n + 1].v = d[n + 1] - d[n], g[n + 1].use = 0, g[n + 1].index = n + 1; 67 int ans = 0, cnt = 0, cnt_index = n + 1; 68 while (que.size() && cnt < k) { 69 gg tg = que.top(); que.pop(); 70 int index = tg.index; 71 if (g[index].use) continue; 72 //printf("l = %d, r = %d, v = %d\n", tg.l, tg.r, tg.v); 73 int pre = g[index].l, nex = g[index].r; 74 int new_pre = pre, new_nex = nex; 75 g[pre].use = g[nex].use = 1; 76 if (1 != new_pre) { 77 new_pre = g[new_pre].l; 78 } 79 if (n + 1 != new_nex) { 80 new_nex = g[new_nex].r; 81 } 82 ans += tg.v; 83 ++cnt_index; 84 g[cnt_index] = gg(new_pre, new_nex, g[pre].v + g[nex].v - tg.v, 0, cnt_index); 85 que.push(g[cnt_index]); 86 g[new_pre].r = g[new_nex].l = cnt_index; 87 ++cnt; 88 } 89 printf("%d\n", ans); 90 return 0; 91 }