[BZOJ1150][CTSC2007]数据备份
题目描述
你在一家 \(IT\)公司为大型写字楼或办公楼的计算机数据做备份。然而数据备份的工作是枯燥乏味的,因此你想设计一个系统让不同的办公楼彼此之间互相备份,而你则坐在家中尽享计算机游戏的乐趣。已知办公楼都位于同一条街上。你决定给这些办公楼配对(两个一组)。每一对办公楼可以通过在这两个建筑物之间铺设网络电缆使得它们可以互相备份。然而,网络电缆的费用很高。
当地电信公司仅能为你提供\(K\) 条网络电缆,这意味着你仅能为 \(K\)对办公楼(或总计\(2K\)个办公楼)安排备份。任一个办公楼都属于唯一的配对组(换句话说,这 \(2K\)个办公楼一定是相异的)。此外,电信公司需按网络电缆的长度(公里数)收费。
因而,你需要选择这 \(K\) 对办公楼使得电缆的总长度尽可能短。换句话说,你需要选择这 \(K\)对办公楼,使得每一对办公楼之间的距离之和(总距离)尽可能小。
下面给出一个示例,假定你有 \(5\) 个客户,其办公楼都在一条街上。这 \(5\) 个办公楼分别位于距离大街起点 \(1km, 3km, 4km, 6km\) 和 \(12km\) 处。电信公司仅为你提供 \(K=2\) 条电缆。
上例中最好的配对方案是将第 \(1\) 个和第$ 2$ 个办公楼相连,第 \(3\) 个和第 \(4\) 个办公楼相连。这样可按要求使用\(K=2\) 条电缆。第 \(1\) 条电缆的长度是 \(3\)km-\(1\)km=\(2\)km ,第$ 2$ 条电缆的长度是$ 6$km-\(4\)km=\(2\)km。这种配对方案需要总长\(4\)km 的网络电缆,满足距离之和最小的要求。
Input
输入的第一行包含整数\(n\)和\(k\),其中\(n(2 \le n \le 100000)\)表示办公楼的数目,\(k\)表示可利用的网络电缆的数目。
接下来的n行每行仅包含一个整数$ (0\le s \le 1000000000) $, 表示每个办公楼到大街起点处的距离。
这些整数将按照从小到大的顺序依次出现。
Output
输出应由一个正整数组成,给出将\(2K\)个相异的办公楼连成\(k\)对所需的网络电缆的最小总长度。
Sample Input
5 2
1
3
4
6
12
Sample Output
4
可反悔的贪心!!!
看到题面,很显然可以得到每栋写字楼必定要
和其相邻的写字楼相连接。
很自然的用堆来维护。
可是否是每次将堆顶的未取线段取走,并打标记呢?
由样例就可以看出,这是不行的。。
那么该怎么办呢?
于是我们要给程序一个“后悔“的机会:将弹出的两侧办公楼对合为一对,其距离为两个办公楼对的距离和-弹出的办公楼距离。
这样我们取这个对的时候就相当于减去了中间的对而取了旁边两侧的对,就是一个“后悔”的过程啦!
维护两侧的对可以用链表来实现。
注意一定要清空有关变量;
代码如下
#include<bits/stdc++.h>
using namespace std;
#define reg register
#define rep(a,b,c) for(reg int a=(b),a##_end_=(c); a<=a##_end_; ++a)
#define drep(a,b,c) for(reg int a=(b),a##_end_=(c); a>=a##_end_; --a)
#define debug(x) cerr<<#x<<" = "<<x<<endl;
int Read() {
int res=0,f=1;
char c;
while(c=getchar(),c<48)if(c=='-')f=-1;
do res=(res<<3)+(res<<1)+(c^48);
while(c=getchar(),c>=48);
return res*f;
}
void Min(double &A,double B) {
if(A>B)A=B;
}
const int M=1e5+5;
int n,k,Ans,A[M],S[M],L[M],R[M];
bool vis[M];
void Add(int num) {
L[num]=num-1,R[num]=num+1;
}
void Del(int num) {
vis[num]=1;
L[R[num]]=L[num];
R[L[num]]=R[num];
}
struct node {
int id;
bool operator<(node _)const {
return S[id]>S[_.id];
}
};
priority_queue<node>Q;
int main() {
n=Read(),k=Read();
rep(i,1,n)A[i]=Read(),L[i]=i-1,R[i]=i+1;
rep(i,1,n-1) {
S[i]=A[i+1]-A[i];
Q.push((node)<%i%>);
}
S[0]=S[n]=1e9;
rep(i,1,k){
node Now=Q.top();
Q.pop();
if(vis[Now.id]) {
i--;
continue;
}
Ans+=S[Now.id];
S[Now.id]=S[L[Now.id]]+S[R[Now.id]]-S[Now.id];
Del(L[Now.id]),Del(R[Now.id]);
Q.push((node)<%Now.id%>);
}
printf("%d",Ans);
}