洛谷P3620/BZOJ1150[APIO/CTSC2007]数据压缩(贪心)
显然k条数据线不会交叉。因此可以把问题转化为:从n-1个区间中选择k个,选出的区间不能相邻,最小化区间长度和。
这个贪心和种树是一样的,只不过1和n-1不相邻,两边放上inf值作边界即可。
#include<cstdio> #include<queue> using namespace std; const int N=100050; char rB[1<<21],*rS,*rT; inline char gc(){return rS==rT&&(rT=(rS=rB)+fread(rB,1,1<<21,stdin),rS==rT)?EOF:*rS++;} inline int rd(){ char c=gc(); while(c<48||c>58)c=gc(); int x=c&15; for(c=gc();c>=48&&c<=57;c=gc())x=(x<<3)+(x<<1)+(c&15); return x; } int a[N],lst[N],nxt[N]; bool vis[N]; struct cmp{ inline bool operator ()(int x,int y){return a[x]>a[y];} }; priority_queue<int,vector<int>,cmp> Q; int main(){ int n=rd(),k=rd(),i,p,x=rd(),y,ans=0; for(i=1;i<n;++i){ a[i]=(y=rd())-x; lst[i]=i-1;nxt[i]=i+1; Q.push(i); x=y; } a[0]=a[n]=0x3f3f3f3f; while(k--){ do{ p=Q.top();Q.pop(); }while(vis[p]); ans+=a[p]; a[p]=a[lst[p]]+a[nxt[p]]-a[p]; vis[lst[p]]=vis[nxt[p]]=1; nxt[lst[p]=lst[lst[p]]]=p;lst[nxt[p]=nxt[nxt[p]]]=p; Q.push(p); } printf("%d",ans); return 0; }