BZOJ1150:[APIO/CTSC2007]數據備份——題解
阿新 • • 發佈:2018-06-23
name load 電信 int include nbsp mat 每次 貪心
https://www.lydsy.com/JudgeOnline/problem.php?id=1150
你在一家 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)維的題。
發現了我們只能取相鄰兩個辦公樓之後我們就能夠寫出dp了,就不說了。
正解考慮貪心去取:我們將每一對辦公樓的距離加入到堆裏面,然後每次彈出最小,並且彈出的兩側辦公樓對就不能再取了。是否可以呢?
顯然是不行的,你會發現樣例就是個反例:2 1 2 6,你取完1之後只能取6,結果輸出了7。
於是我們要給程序一個“後悔“的機會:將彈出的兩側辦公樓對合為一對,其距離為兩個辦公樓對的距離和-彈出的辦公樓距離。
這樣我們取這個對的時候就相當於減去了中間的對而取了旁邊兩側的對,就是一個“後悔”的過程啦!
維護兩側的對可以用鏈表來實現。
#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。 +
+歡迎訪問我的博客:http://www.cnblogs.com/luyouqi233/ +
+++++++++++++++++++++++++++++++++++++++++++
BZOJ1150:[APIO/CTSC2007]數據備份——題解