1150: [CTSC2007]数据备份Backup
https://lydsy.com/JudgeOnline/problem.php?id=1150
分析:
堆+贪心。
每次选最小的并一定是最优的,如果不选这个最小的,那一定是为了取它左右两边(两条都要取才可能比当前优)。
如果先选了最小的,考虑后面如何撤销。选了这个后,左右两边的线段就要删了,那么在加入一个长度为:左边的长度+右边的长度-当前的线段的长度 的一条线段。
代码:
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<iostream>
#include<cmath>
#include<cctype>
#include<set>
#include<queue>
#include<vector>
#include<map>
using namespace std;
typedef long long LL; inline int read() {
int x=,f=;char ch=getchar();for(;!isdigit(ch);ch=getchar())if(ch=='-')f=-;
for(;isdigit(ch);ch=getchar())x=x*+ch-'';return x*f;
} const int N = ;
const int INF = 1e9; int pre[N], nxt[N], d[N], a[N];
bool vis[N]; struct Edge{
int len, id;
Edge() { }
Edge(int a, int b) { len = a, id = b; }
bool operator < (const Edge &A) const {
return len > A.len;
}
};
priority_queue<Edge> q; void del(int i) {
vis[i] = ;
nxt[pre[i]] = nxt[i];
pre[nxt[i]] = pre[i];
} int main() {
int n = read(), m = read();
for (int i = ; i <= n; ++i) d[i] = read();
for (int i = ; i < n; ++i) {
a[i] = d[i + ] - d[i];
q.push(Edge(a[i], i));
}
a[] = a[n] = INF;
for (int i = ; i <= n; ++i) pre[i] = i - , nxt[i] = i + ;
int ans = ;
while (m --) {
while (vis[q.top().id]) q.pop();
Edge now = q.top(); q.pop();
ans += now.len;
int i = now.id, t;
t = min(a[pre[i]] + a[nxt[i]] - now.len, INF);
del(pre[i]); del(nxt[i]);
a[i] = t; q.push(Edge(a[i], i));
}
cout << ans;
return ;
}