題目
在離著名的國家Berland不遠的地方,有一個水下工作站。這個工作站有N層。已知:是第層裝有Wi的水,最多可以容納Li的水,恐怖分子炸毀第i的代價是Pi。第i層一旦被炸毀,該層所有的水都將傾瀉到第i+1層。如果某一層的水量超過了它的容量(即Li),那么該層就將自動被毀壞,所有的水也會傾瀉到下一層。
Pivland的恐怖分子想要用最少的錢毀掉第N層,現在他雇傭你來計算,需要炸毀哪些層。
輸入
第一行有一個自然數N(1<=n<=15000)。接下來的N行,每行3個整數Wi, Li, Pi(0<=Wi,Li,Pi<=15000)。
輸出
輸出需要炸毀的層的編號。
Solution1:小根堆+枚舉。
從下往上推的話,f[i]是從i層開始炸毀的代價如果炸毀i-1,且s[i]-s[i-2]>l[i],那么從第i-1層開始炸毀的代價是f[i]+c[i-1]-c[i]; 從第k層開始炸毀時只要將第i(k<i<=n)層里(s[i]-s[k-1]>l[i]) 層里之前算作炸毀的層的c[i]減去,并標記沒被炸毀.用優先隊列優化的話將快很多,只要將當前炸毀的層入隊,當滿足s[i]-s[k-1]>l[i]時,出隊并減去c[i];
#include <cstdio> #include <queue> #include <utility> using namespace std; typedef pair<int,int> aii;const int maxx = 15000+10, INF = 2e9; PRiority_queue< aii > heap;int n;int ans = INF,flag = 0,sum = 0,Sum = 0; int v[maxx],s[maxx],c[maxx];int pre[maxx];bool hash[maxx];int main() { // freopen("Bstation.in","r",stdin);// freopen("Bstation.out","w",stdout); scanf("%d",&n); for(int i=n;i>=1;i--) { scanf("%d%d%d",&s[i],&v[i],&c[i]); pre[i] = pre[i+1]+s[i]; } for(int i=1;i<=n;i++) { for(;!heap.empty() && heap.top().first>pre[i+1]; heap.pop()) sum -= heap.top().second; heap.push(make_pair(pre[i]-v[i], c[i])); sum+=c[i]; if(ans>sum) { ans = sum; flag = i; } } for(int i=flag;i>=1;i--) { Sum += s[i]; if(Sum>v[i]) hash[i] = true; } for(int i=flag;i>=1;i--) if(!hash[i]) printf("%d/n", n-i+1); return 0; }Solution2:類似二分查找的算法。之前做過B-station,是用堆的方法。奈何考場碰到此題時早已把此方法忘得一干二凈/捂臉。所以迫不得已,強行自己創造了
一個類似二分查找的方法來通過此題防止爆零…咳咳咳,這個方法大致是這樣的。讀入時首先處理(由于本人個人習慣原因,把最高
層叫做第一層。要炸的叫最底層)之后用sum[i]表示重量的前綴和,用val[i]表示炸該層的費用。之后把每層放入結構體。關鍵字:
d,l,w,id,need(need保存的是壓毀此層時至少毀掉的最高層。換句話說,設i層的need為need[i],只要從need[i]到i-1之間
所有層都已毀壞,第i層就會直接被壓毀。而這個need怎么求呢?假設第i層的need[i]為T,則有sum[i]-sum[T-1]>l[i]。經變形得
到sum[T-1]<sum[i]-l[i]。這時候,因為sum單調遞增,可知sum[T]>=sum[i]-l[i]。所以可以用lower_bound函數直接找出
need[i]。接下來我們要做的是將結構體依照need進行排序。然后創建一個vector<int> sale[]的數組。sale[i]中存以此層作為最
高層時可以壓毀的層的編號。之后就直接自底往上開始枚舉最高層。每次枚舉時首先tmp += val[i](都考慮直接炸掉),之后在
sale[i]中進行查找,如果有編號在i層和底層之間,也就是sale[i][j]>i,則tmp-=val[sale[i][j]]。(說明以i為最高層時此層不用
炸)。每次枚舉過后比較tmp與Ans。最終就能得到答案。//考試時做了幾個小時,生無可戀.jpg。
#include <cstdio>#include <algorithm>#include <queue>#include <vector>using namespace std;const int maxx = 100000 + 100;struct Edge{ int id; int d; int l; int w; int need;}Edges[maxx];long long sum[maxx],val[maxx],cost[maxx];long long Ans = 1e9 + 100,tmp;int n;vector <int> sale[maxx];bool cmp(Edge a,Edge b){ if(a.need != b.need) return a.need<b.need; else return a.id<b.id;}int main(){// freopen("Bomb.in","r",stdin);// freopen("Bomb.out","w",stdout); scanf("%d",&n); for(int i=n;i>=1;i--){ scanf("%d%d%d",&Edges[i].d,&Edges[i].w,&Edges[i].l); val[i]=Edges[i].d; Edges[i].id = i; } for(int i=1;i<=n;i++) sum[i]=sum[i-1]+Edges[i].w; for(int i=1;i<=n;i++){ int T = lower_bound(sum,sum+i,sum[i]-Edges[i].l)-sum; if(T>0) Edges[i].need = T; else Edges[i].need = 0; } sort(Edges+1,Edges+n+1,cmp); for(int i=1;i<=n;i++) sale[Edges[i].need].push_back(Edges[i].id); for(int i=n;i>=1;i--){ tmp += val[i]; for(int j=0;j<sale[i].size();j++){ if(sale[i][j]>i) tmp -= val[sale[i][j]]; } Ans = min(Ans,tmp); } printf("%d",Ans); return 0;}看來做過的題目還是要好好學懂啊QvQ。
新聞熱點
疑難解答