777E Report
题意:
给出一些Hanoi tower的环的信息,分别为内径大小,外径大小和环的高度,要求这些环从下到上外径不减,且上层ring的外径必须大于下层的内径,求出可行的最大高度。
题解:
因为这道题我已经在考试后订正了,而且算法与两标程的相同,所以直接开始题解的部分。
读完题目,我的第一反应是用图还原样例,但是图示画到一半我就发现可以直接用线段来表示这些ring。对于某一个内径为ai、外径为bi的ring,在线段上被表示为一条从ai到bi的线段。那么数轴从小到大对应的就是tower上的从上到下。
考虑完模型的转化之后,考虑模型中各个ring的相互关系。由题意可知,一个ring可以承载另一个ring必须满足内径小于另一个ring的外径,且外径必须大于等于另一个ring的外径。那么这种关系表示在线段上就是:
这里要注意的就是Aj!=Bi,因为内外径相等会掉下去的。
这样就直接把问题转化到了线段上,但是目标不是获得尽可能长的线段,而是获得尽可能高的高度。换句话说,就是线段上各有一些权值,需要获得尽可能多的权值。
我们已知两个性质:
- 如果可以选的话,选总比不选要好;
- 我们希望,在顺次枚举线段一端的时候,另一端距离这端越远越好。因为距离越远, 就有越大的可能去再续上另一条线段。
所以说这道题贪心可做,维护一个stack表示当前选到的线段。贪心之前按照上述思路,将这些线段以bi为第一关键字,ai为第二关键字从大到小排序。然后扫一遍,如果能放进栈里就压栈,不能的话就弹到能放为止,同时维护当前高度和最高高度。
复杂度:
因为每一个ring至多进栈一次,出栈一次,所以统计答案是O(n)的,排序需要O(nlogn),所以整体的复杂度为O(nlongn)。
代码:
很短。
#include <cstdio>
#include <stack>
#include <algorithm>
using namespace std;
const int maxn=int(1e5)+10;
int n;
long long ans=0,cur=0;
stack<int> s;
struct Hanoi {
int a,b,h;
bool operator < (const Hanoi &x) const {return (b^x.b)?(b>x.b):(a>x.a);}
void read() {scanf("%d%d%d",&a,&b,&h);}
}r[maxn];
int main() {
scanf("%d",&n);
for(int i=0;i<n;i++) r[i].read();
sort(r,r+n);
for(int i=0;i<n;i++) {
while(s.size() && r[s.top()].a>=r[i].b) {
cur-=r[s.top()].h;
s.pop();
}
s.push(i);
cur+=r[i].h;
ans=max(ans,cur);
}
printf("%I64d\n",ans);
return 0;
}