传送门:www.lydsy.com/JudgeOnline/problem.php?id=1150
dp会T……于是得YY新做法……
每次贪心最小的线段很明显是错误的,于是可以每次取最小的时候,删除其左右线段,加入一个新线段,权值为 左+右-中 前驱后继线段分别为左前驱右后继,这样贪心就“能够改正自己的错误”,比如样例,先取了2-3 ,加入新线段 又取了1-2 + 3-4 - 2-3 这条新线段,总和恰好是1-2 与3-4 的权值和,这样就“修正了错误”,贪心就是正确的了……
Code:
#include<set>
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<climits>
using namespace std;
typedef long long lld;
typedef pair<lld,lld> pii;
const lld maxn=100010;
set<pii>heap;
lld n,m;
lld getlld(){
lld res=0,ok=0;char ch;
while(1){
ch=getchar();
if(ch>='0'&&ch<='9'){
res*=10;res+=ch-'0';ok=1;
}else if(ok)break;
}return res;
}
lld a[maxn];
lld b[maxn];
lld l[maxn];
lld r[maxn];
int main(){
n=getlld();m=getlld();
for(lld i=1;i<=n;i++)a[i]=getlld();
for(lld i=2;i<=n;i++){
b[i]=a[i]-a[i-1];
l[i]=i-1;
r[i]=i+1;
heap.insert(pii(b[i],i));
}
b[1]=1LL<<61;
r[1]=2;heap.insert(pii(b[1],1));
b[n+1]=1LL<<61;
l[n+1]=n;heap.insert(pii(b[n+1],n+1));
long long ans=0;
while(m--){
set<pii>::iterator it=heap.begin();
ans+=it->first;
lld pn=it->second,pl=l[it->second],pr=r[it->second];
l[pn]=l[pl];r[l[pl]]=pn;
r[pn]=r[pr];l[r[pr]]=pn;
b[pn]=b[pl]+b[pr]-b[pn];
heap.erase(*it);
heap.erase(pii(b[pr],pr));
heap.erase(pii(b[pl],pl));
heap.insert(pii(b[pn],pn));
}
cout<<ans<<endl;
return 0;
}