bzoj1150: [CTSC2007]数据备份Backup

题目链接

bzoj1150

题目描述

Description

bzoj1150: [CTSC2007]数据备份Backup_第1张图片

Input

输入的第一行包含整数n和k,其中n(2 ≤ n ≤100 000)表示办公楼的数目,k(1≤ k≤ n/2)表示可利用的网络电缆的数目。接下来的n行每行仅包含一个整数(0≤ s ≤1000 000 000), 表示每个办公楼到大街起点处的距离。这些整数将按照从小到大的顺序依次出现。

Output

输出应由一个正整数组成,给出将2K个相异的办公楼连成k对所需的网络电缆的最小总长度。

Sample Input

5 2
1
3
4
6
12

Sample Output

4

HINT

上面的样例输入给出了前面描述的示例情形 对于每一个测试点,如果写到输出文件中的答案正确,则得到该测试点100%的分数,否则得零分。30%的输入数据满足n≤20。60%的输入数据满足n≤10 000。

题解

一道贪心好题。
差分一下将问题转化为从n个数中选k个,任意两个不能相邻,使得k个数的和最小。如果每次都选最小的,将它相邻的删掉,这样贪心是有问题的。比方说100,2,1,2中选两个,我们会选1和100。而最优方案为两个2。为什么会有这种情况?当我们选了第x个数时,会对第x+1和x-1个数产生影响。有可能选x-1和x+1而不选x会更优(一定是x-1和x+1同时选)。我们可以这样调整。选了第x个数后将a[x-1]+a[x+1]-a[x]加入,并删除x,x-1,x+1。这样当我们选了这个数就意味着选第x+1,x-1个数而不选x。只有维护一个前驱后继,再用堆来做就行了。

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<queue>
#include<vector>
using namespace std;

#define mp make_pair
#define N 100010
#define se second
typedef pair<int,int>P;
priority_queue<P> h;
P tmp;
int n,k,ans,a[N],pre[N],suc[N]; 

char BUF[200001],*buf,*end;
#define getch() (buf==end?fread(BUF,1,200000,stdin),buf=BUF,end=buf+200000,*(buf++):*(buf++))
inline void read(int &x){
    static char c;
    for(c=getch();c<'0'||c>'9';c=getch());
    for(x=0;'0'<=c&&c<='9';c=getch())x=x*10+c-'0';
}

int main(){
    read(n); read(k); n--;
    for(int i=1;i<=n+1;i++) read(a[i]);
    for(int i=1;i<=n;i++) a[i]=a[i+1]-a[i];
    for(int i=1;i<n;i++) pre[i]=i+1;
    for(int i=2;i<=n;i++) suc[i]=i-1;
    for(int i=1;i<=n;i++) h.push(mp(-a[i],i));
    for(int i=1;i<=k;i++){
        while(-h.top().first!=a[h.top().se]) h.pop();
        tmp=h.top(); h.pop();
        ans-=tmp.first;
        if(pre[tmp.se]&&suc[tmp.se]){
            a[tmp.se]=a[pre[tmp.se]]+a[suc[tmp.se]]-a[tmp.se];
            a[pre[tmp.se]]=a[suc[tmp.se]]=1000000007;
            pre[tmp.se]=pre[pre[tmp.se]];
            suc[tmp.se]=suc[suc[tmp.se]];
            suc[pre[tmp.se]]=pre[suc[tmp.se]]=tmp.se;
            h.push(mp(-a[tmp.se],tmp.se));
        } else{
            a[pre[tmp.se]]=a[suc[tmp.se]]=1000000007;
            pre[tmp.se]=pre[pre[tmp.se]];
            suc[tmp.se]=suc[suc[tmp.se]];
            suc[pre[tmp.se]]=pre[suc[tmp.se]]=0;
        }
    }
    printf("%d\n",ans);
    return 0;
}

你可能感兴趣的:(bzoj1150: [CTSC2007]数据备份Backup)