发射站(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;
}