原題傳送門
首先轉化題意,可以用貪心策略證明肯定是相鄰的兩個點建立電纜
然後把問題轉化成,中取個不相鄰的數使得和最小
首先非常明顯的,可以拿到60分的好成績
然後考慮優化,dp上狀態已經,到頂了,除非設計更妙的狀態,但是數據範圍告訴我們,需要一個的做法
於是想到反悔貪心
從頭思考,一個非常的貪心,維護優先隊列,每次取最小的,並且把左右兩個打上標記,因爲相鄰的兩個不能都選,這樣取次即可
顯然,但是我們可以增添一個反悔機制,每次從優先隊列取出一個未標記的值時,首先這個值肯定合理並且當前最優,那麼就加入答案,但是這個值不一定全局最優,所以以後可能反悔,那麼怎麼反悔呢,當然就是不選這個值了,改選這個值左右兩邊的兩個值
具體流程就是對於一個取出的值,統計答案,並且將值加入優先隊列,這樣依然是做次,因爲每做一次就會多一個數
然後不要忘了打標記,這裏我們需要用雙向隊列維護一下左右兩邊的值
Code:
#include <bits/stdc++.h>
#define maxn 100010
using namespace std;
struct node{
int num, val;
bool operator < (const node &x) const{ return x.val < val; }
};
priority_queue <node> q;
struct data{
int l, r, val;
}a[maxn];
int n, k, vis[maxn], ans;
inline int read(){
int s = 0, w = 1;
char c = getchar();
for (; !isdigit(c); c = getchar()) if (c == '-') w = -1;
for (; isdigit(c); c = getchar()) s = (s << 1) + (s << 3) + (c ^ 48);
return s * w;
}
void del(int x){
a[x].l = a[a[x].l].l, a[x].r = a[a[x].r].r,
a[a[x].l].r = x, a[a[x].r].l = x;
}
int main(){
n = read(), k = read();
int Last = read();
for (int i = 1; i < n; ++i){
int x = read();
a[i].val = x - Last, Last = x, a[i].l = i - 1, a[i].r = i + 1;
q.push((node){i, a[i].val});
}
a[0].val = a[n].val = 1e9;
for (int i = 1; i <= k; ++i){
while (vis[q.top().num]) q.pop();
node tmp = q.top(); q.pop();
ans += tmp.val;
vis[a[tmp.num].l] = vis[a[tmp.num].r] = 1;
a[tmp.num].val = a[a[tmp.num].l].val + a[a[tmp.num].r].val - a[tmp.num].val;
q.push((node){tmp.num, a[tmp.num].val});
del(tmp.num);
}
printf("%d\n", ans);
return 0;
}