BZOJ1150:[APIO/CTSC2007]數據備份——題解

https://www.lydsy.com/JudgeOnline/problem.php?id=1150php

你在一家 IT 公司爲大型寫字樓或辦公樓(offices)的計算機數據作備份。然而數據備份的工做是枯燥乏味的,所以你想設計一個系統讓不一樣的辦公樓彼此之間互相備份,而你則坐在家中盡享計算機遊戲的樂趣。
已知辦公樓都位於同一條街上。你決定給這些辦公樓配對(兩個一組)。每一對辦公樓能夠經過在這兩個建築物之間鋪設網絡電纜使得它們能夠互相備份。
然而,網絡電纜的費用很高。當地電信公司僅能爲你提供 K 條網絡電纜,這意味着你僅能爲 K 對辦公樓(或總計2K個辦公樓)安排備份。任一個辦公樓都屬於惟一的配對組(換句話說,這 2K個辦公樓必定是相異的)。
此外,電信公司需按網絡電纜的長度(千米數)收費。於是,你須要選擇這 K 對辦公樓使得電纜的總長度儘量短。換句話說,你須要選擇這 K 對辦公樓,使得每一對辦公樓之間的距離之和(總距離)儘量小。
下面給出一個示例,假定你有 5 個客戶,其辦公樓都在一條街上,以下圖所示。這 5 個辦公樓分別位於距離大街起點 1km, 3km, 4km, 6km 和 12km 處。電信公司僅爲你提供 K=2 條電纜。
上例中最好的配對方案是將第 1 個和第 2 個辦公樓相連,第 3 個和第 4 個辦公樓相連。這樣可按要求使用 K=2 條電纜。第 1 條電纜的長度是 3km-1km=2km ,第 2 條電纜的長度是 6km-4km=2km。這種配對方案須要總長 4km 的網絡電纜,知足距離之和最小的要求。

一道須要些簡單思(trick)維的題。ios

發現了咱們只能取相鄰兩個辦公樓以後咱們就可以寫出dp了,就不說了。git

正解考慮貪心去取:咱們將每一對辦公樓的距離加入到堆裏面,而後每次彈出最小,而且彈出的兩側辦公樓對就不能再取了。是否能夠呢?網絡

顯然是不行的,你會發現樣例就是個反例:2 1 2 6,你取完1以後只能取6,結果輸出了7。spa

因而咱們要給程序一個「後悔「的機會:將彈出的兩側辦公樓對合爲一對,其距離爲兩個辦公樓對的距離和-彈出的辦公樓距離。設計

這樣咱們取這個對的時候就至關於減去了中間的對而取了旁邊兩側的對,就是一個「後悔」的過程啦!code

維護兩側的對能夠用鏈表來實現。blog

#include<map>
#include<cmath>
#include<stack>
#include<queue>
#include<cstdio>
#include<cctype>
#include<vector>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
#define fi first
#define se second
const int N=1e5+5;
const int INF=1e9+1;
inline int read(){
    int X=0,w=0;char ch=0;
    while(!isdigit(ch)){w|=ch=='-';ch=getchar();}
    while(isdigit(ch))X=(X<<3)+(X<<1)+(ch^48),ch=getchar();
    return w?-X:X;
}
map<pii,bool>mp;
priority_queue<pii,vector<pii>,greater<pii> >q;
int n,k,a[N],pre[N],nxt[N];
int main(){
    n=read(),k=read();
    for(int i=1;i<=n;i++)a[i]=read();
    for(int i=1;i<n;i++){
        a[i]=a[i+1]-a[i];
        pre[i]=i-1;nxt[i-1]=i;
        q.push(pii(a[i],i));
    }
    nxt[n-1]=n;pre[0]=0;nxt[n]=n;a[0]=a[n]=INF;
    int ans=0;
    while(k--){
        pii p=q.top();q.pop();
        if(mp.count(p)){k++;mp.erase(p);continue;}
        ans+=p.fi;
        a[p.se]=a[pre[p.se]]+a[nxt[p.se]]-p.fi;
        mp[pii(a[pre[p.se]],pre[p.se])]=1;
        mp[pii(a[nxt[p.se]],nxt[p.se])]=1;
        q.push(pii(a[p.se],p.se));
        pre[p.se]=pre[pre[p.se]];
        nxt[p.se]=nxt[nxt[p.se]];
        nxt[pre[p.se]]=p.se;
        pre[nxt[p.se]]=p.se;
    }
    printf("%d\n",ans);
    return 0;
}

+++++++++++++++++++++++++++++++++++++++++++遊戲

+本文做者:luyouqi233。               +get

+歡迎訪問個人博客:http://www.cnblogs.com/luyouqi233/ +

+++++++++++++++++++++++++++++++++++++++++++

相關文章
相關標籤/搜索