传送门: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; }