bzoj1150: [CTSC2007]數據備份Backup

題目鏈接

bzoj1150

題目描述

Description

這裏寫圖片描述

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;
}
發佈了60 篇原創文章 · 獲贊 8 · 訪問量 3萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章