洛谷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;
}
View Code

 

posted @ 2019-08-27 14:35  wangyuchen  阅读(161)  评论(0编辑  收藏  举报