题目链接:http://acm.sgu.ru/problem.php?contest=0&problem=148
题意:在离著名的国家Berland不远的地方,有一个水下工作站。这个工作站有N层。已知:是第i层装有Wi的水,最多可以容纳Li的水,恐怖分子炸毁第i层的代价是Pi。第i层一旦被炸毁,该层所有的水都将倾泻到第i+1层。如果某一层的水量超过了它的容量(即Li),那么该层就将自动被毁坏,所有的水也会倾泻到下一层。Pivland的恐怖分子想要用最少的钱毁掉第N层,现在他雇佣你来计算,需要炸毁哪些层。
思路:令Si=W1+W2+…+Wi(特别的,S0=0)。不妨设恐怖分子炸毁的第高层是第p层(第一层是最高层,第N层是最底层)。因为恐怖分子的目标是毁灭第N层,所以水必须从第p层一直泻下去。如果存在一个i(i>p),满足Wp+Wp+1+…+Wi-1+Wi<=Li,也就是说前面几层的水全部泄下来也无法把第i层自动冲毁,那么就必须要把它炸开了。所以恐怖分子需要炸毁的层的集合就是Bomb[p]={p}∪{i |i>p Si-Sp-1<=Li}。令Wi=Si-Li,那么:Bomb[p]={p}∪{i |i>p Wi<=Sp-1}。因此枚举p,然后看哪些层需要炸毁。这样就得到了一个O(n2)的算法。
注意到Sp是随着p的增加而递增的,观察两个集合:
Bomb[p]={p}∪{i |i>p Wi<=Sp-1}
Bomb[p-1]={p-1}∪{i |i>p-1 Wi<=Sp-2}
因为Sp-2<=Sp-1,所以{i |i>p-1 Wi<=Sp-2}Bomb[p]。
也就是说,Bomb[p-1]是在Bomb[p]的基础上,通过以下操作得到的:
1. 删除所有的i∈Bomb[p],Wi>Sp-2。
2. 添加p-1。
针对这两种操作,我们可以使用大根堆(Heap)。从大到小枚举p,对于每一个p,执行:
Step1. 如果堆的根>Sp-1,那么删除根;否则转Step3。
Step2. 转Step1。
Step3. 添加p,同时更新答案。
1 struct node 2 { 3 int w,id; 4 5 node(){} 6 node(int _w,int _id) 7 { 8 w=_w; 9 id=_id; 10 } 11 }; 12 13 const int INF=1000000000; 14 const int MAX=15005; 15 int n,W[MAX],L[MAX],P[MAX],aSize; 16 int S[MAX]; 17 node a[MAX<<2]; 18 19 void down(int t) 20 { 21 int L,R,k; 22 while(1) 23 { 24 L=t*2; 25 R=t*2+1; 26 if(L<=aSize&&a[L].w>a[t].w) k=L; 27 else k=t; 28 if(R<=aSize&&a[R].w>a[k].w) k=R; 29 if(k==t) break; 30 swap(a[k],a[t]); 31 t=k; 32 } 33 } 34 35 void up(int t) 36 { 37 int p=t/2; 38 while(p>=1) 39 { 40 if(a[p].w<a[t].w) swap(a[p],a[t]); 41 else break; 42 t=p; 43 p=t/2; 44 } 45 } 46 47 int cmp(node a,node b) 48 { 49 return a.id<b.id; 50 } 51 52 int main() 53 { 54 RD(n); 55 int i; 56 FOR1(i,n) 57 { 58 RD(W[i],L[i],P[i]); 59 S[i]=S[i-1]+W[i]; 60 W[i]=S[i]-L[i]; 61 } 62 aSize=0; 63 int ans=INF,p,cur=0; 64 DOW1(p,n) 65 { 66 while(aSize>0&&a[1].w>S[p-1]) 67 { 68 cur-=P[a[1].id]; 69 a[1]=a[aSize--]; 70 down(1); 71 } 72 a[++aSize]=node(W[p],p); 73 up(aSize); 74 cur+=P[p]; 75 ans=min(ans,cur); 76 } 77 aSize=0; 78 int tempAns=INF; 79 cur=0; 80 DOW1(p,n) 81 { 82 while(aSize>0&&a[1].w>S[p-1]) 83 { 84 cur-=P[a[1].id]; 85 a[1]=a[aSize--]; 86 down(1); 87 } 88 a[++aSize]=node(W[p],p); 89 up(aSize); 90 cur+=P[p]; 91 tempAns=min(tempAns,cur); 92 if(tempAns==ans) break; 93 } 94 sort(a+1,a+aSize+1,cmp); 95 FOR1(i,aSize) PR(a[i].id); 96 return 0; 97 }