发射站(2017佛山市选拔初中组)
发射站(2017佛山市选拔初中组)
题目描述
有N个能量发射站排成一行,每个发射站i都有不相同的高度 Hi,并能向两边(当然两端的只能向一边)同时发射能量值为Vi的能量,并且发出的能量只被两边最近的且比它高的发射站接收。
显然每个发射站发来的能量有可能被0或1或2个其它发射站接收,特别是为了安全,它受到的能量总和是我们很关心的。由于数据很多,请你帮助我们计算出接受了最多能量的发射站接受的能量是多少。
【数据范围】
1≤N≤800,000;1≤hi≤2,000,000,000;1≤vi≤10,000。
输入格式 1756.in
第1行:一个整数 N;
第2..N+1行:第i+1行有2个整数Hi和Vi,表示第i个发射站的高和发射的能量值。
输出格式 1756.out
一行:一个发射站接收到的最大能量值。
输入样例 1756.in
3
4 2
3 5
6 10
输出样例 1756.out
【提示】
第3个发射站可接受第1和第2个发射的能量:2+5=7
【输入样例2】
4
1 2
3 1
7 5
2 3
【输出样例2】
4
【提示】
第三个发射站可接受第2个和第四个发射的能量 :1+3=4
这一题其实在暴力的基础上加一点小的优化就可以A。
其实就是要找前(后)比当前(now)高的第一个。当我们从左往右找的时候,其实就已经是计算出前面的了。那么如果前一个比now高,那么就是前一个;否则,那比前面还矮的就不必搜索了,因为既然你比前面的高,比前面矮的自然也不会比now高。所以,我们可以记录下每一个比它高的那个的位置l和r。
在now时,直接由l[now-1]往前找就可以了,可以省去很多时间,同样的,也从右往左扫一遍,最后取一个能量max值就是最终结果。
参考代码:
#include<iostream> #include<cstdio> using namespace std; int n,h[800005],m[800005]; int l[800005],r[800005],ans[800005],oo=2000000005; int main() { freopen("1756.in","r",stdin); freopen("1756.out","w",stdout); cin>>n; for(int i=1;i<=n;i++) cin>>h[i]>>m[i]; h[0]=oo; h[n+1]=oo; for(int i=1;i<=n;i++) { int v=0; if(h[i]<h[i-1]) { l[i]=i-1; ans[i-1]+=m[i]; } else { v=l[i-1]; for(int j=v;j>=1;j--) { if(h[i]<h[j]) { l[i]=j; ans[j]+=m[i]; break; } } } } for(int i=n;i>=1;i--) { int v=0; if(h[i]<h[i+1]) { r[i]=i+1; ans[i+1]+=m[i]; } else { v=r[i+1]; for(int j=v;j<=n;j++) { if(h[i]<h[j]) { r[i]=j; ans[j]+=m[i]; break; } } } } int ans2=0; for(int i=1;i<=n;i++) { ans2=max(ans2,ans[i]); } cout<<ans2<<endl; return 0; }