https://cn.vjudge.net/problem/HYSBZ-1150
题目
你在一家 IT 公司为大型写字楼或办公楼(offices)的计算机数据做备份。然而数据备份的工作是枯燥乏味的,因此你想设计一个系统让不同的办公楼彼此之间互相备份,而你则坐在家中尽享计算机游戏的乐趣。已知办公楼都位于同一条街上。你决定给这些办公楼配对(两个一组)。每一对办公楼可以通过在这两个建筑物之间铺设网络电缆使得它们可以互相备份。然而,网络电缆的费用很高。当地电信公司仅能为你提供 K 条网络电缆,这意味着你仅能为 K 对办公楼(或总计2K个办公楼)安排备份。任一个办公楼都属于唯一的配对组(换句话说,这 2K 个办公楼一定是相异的)。此外,电信公司需按网络电缆的长度(公里数)收费。因而,你需要选择这 K 对办公楼使得电缆的总长度尽可能短。换句话说,你需要选择这 K 对办公楼,使得每一对办公楼之间的距离之和(总距离)尽可能小。下面给出一个示例,假定你有 5 个客户,其办公楼都在一条街上,如下图所示。这 5 个办公楼分别位于距离大街起点 1km, 3km, 4km, 6km 和 12km 处。电信公司仅为你提供 K=2 条电缆。
上例中最好的配对方案是将第 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
Sample Output
4
题解
贪心,肯定选相邻的楼,于是计算出相邻的距离,转化为一堆数字中选出不相邻的K个数,使和最小
考虑如何选2个
1.先选最小的,再在剩余的不相邻的里面选次小的
2.不选最小的,选两个相邻的,如果选了一个不相邻的+其他,肯定不如选最小的+其他
为了反悔,可以选择以后将选了的最小的数变成$左边+右边-自己$,那么选变了以后的数就相当于选相邻的
由于要把堆和链表一起用,那么可以使用栈集合计算机编号的方法,在堆里面存数据的编号,链表直接使用编号,然后开一个编号转堆下标的数组
AC代码
#include<cstdio>
#include<cctype>
#include<algorithm>
#define REP(r,x,y) for(register int r=(x); r<(y); r++)
#define REPE(r,x,y) for(register int r=(x); r<=(y); r++)
#ifdef sahdsg
#define DBG(...) printf(__VA_ARGS__)
#else
#define DBG(...) void(0)
#endif
using namespace std;int _s; char _c;
template <class T>
void read(T&x) {x=0; do _c=getchar(); while(!isdigit(_c) && _c!='-'); _s=1; if(_c=='-') _s=-1, _c=getchar(); while(isdigit(_c)) { x=x*10+_c-'0'; _c=getchar();} x*=_s;
}#define MAXN 100007
#define MAXK 50007int dt[MAXN];
int hp[MAXN], sh;
int nxt[MAXN], prv[MAXN];
int th[MAXN];//, tl[MAXN];void up(int p) {while(p>1) {if(dt[hp[p]]<dt[hp[p>>1]]) {swap(th[hp[p]], th[hp[p>>1]]);swap(hp[p], hp[p>>1]);p>>=1;} else break;}
}void down(int p) {int s=p<<1;while(s<=sh) {if(s<sh && dt[hp[s+1]]<dt[hp[s]]) s++;if(dt[hp[s]]<dt[hp[p]]) {swap(th[hp[p]], th[hp[s]]);swap(hp[p], hp[s]);p=s; s<<=1;} else break;}
}void remove(int p) {hp[p]=hp[sh--]; th[hp[p]]=p; up(p); down(p);
}void lk(int a, int b) {nxt[a]=b; prv[b]=a;
}int main() {int n,k; read(n); read(k);int now,lst; read(lst);REP(i,1,n) {read(now); int t=now-lst; lst=now;dt[i]=t; hp[++sh]=i; th[i]=sh; nxt[i]=i+1, prv[i]=i-1; up(sh);}int ans=0;REP(c,0,k) {int x=hp[1];ans+=dt[x]; DBG("!%d\n", dt[x]);if(prv[x]==0 && nxt[x]==n) break;if(prv[x] && nxt[x]!=n) {int nd=dt[prv[x]]+dt[nxt[x]]-dt[x];remove(th[prv[x]]); remove(th[nxt[x]]); lk(prv[prv[x]],x); lk(x, nxt[nxt[x]]);remove(th[x]);dt[x]=nd; hp[++sh]=x; th[x]=sh; up(sh);} else if(prv[x]) {remove(th[prv[x]]); nxt[prv[prv[x]]]=n;remove(th[x]);} else {remove(th[nxt[x]]); prv[nxt[nxt[x]]]=0;remove(th[x]);}}printf("%d\n", ans);
}