洛谷P1901 发射站

P1901 发射站

  •  
  • 111通过
  • 206提交
  • 题目提供者该用户不存在
  • 标签NOI导刊
  • 难度普及/提高-

提交    

最新讨论

  • 有人说是单调队列,但不明明…

题目描述

某地有 N 个能量发射站排成一行,每个发射站 i 都有不相同的高度 Hi,并能向两边(当 然两端的只能向一边)同时发射能量值为 Vi 的能量,并且发出的能量只被两边最近的且比 它高的发射站接收。

显然,每个发射站发来的能量有可能被 0 或 1 或 2 个其他发射站所接受,特别是为了安 全,每个发射站接收到的能量总和是我们很关心的问题。由于数据很多,现只需要你帮忙计 算出接收最多能量的发射站接收的能量是多少。

输入输出格式

输入格式:

第 1 行:一个整数 N;

第 2 到 N+1 行:第 i+1 行有两个整数 Hi 和 Vi,表示第 i 个人发射站的高度和发射的能量值。

输出格式:

输出仅一行,表示接收最多能量的发射站接收到的能量值,答案不超过 longint。

输入输出样例

输入样例#1

3

4 2

3 5

6 10

输出样例#1

7

说明

对于 40%的数据,1<=N<=5000;1<=Hi<=100000;1<=Vi<=10000;

对于 70%的数据,1<=N<=100000;1<=Hi<=2,000,000,000;1<=Vi<=10000;

对于 100%的数据,1<=N<=1000000;1<=Hi<=2,000,000,000;1<=Vi<=10000。

分析:看到这道题会很容易想到暴力,写一个O(n^2)暴力似乎只能得到40分,然后想想有没有什么简单方法呢?

     可以发现向左发射能量和向右发射能量的性质是一样的,我们如果能处理向左的自然就能处理向右的,先处理向左的,显然不能一个一个枚举,类似于dp中的填表法和刷表法,如果不能通过其它的“状态”推出当前能量塔的“状态”,那么就用当前能量塔的“状态”去更新其它能量塔的“状态”.

     假设3个能量塔为a,b,c,且是从左到右排序的,那么先假设a<b ,可以证明a对后面的的能量传递是没有作用的,先假设b >c,那么c就会想b传送能量,或者b <= c,那么c将不会像左边的任何能量塔传递能量,所以a的右边不会有能量传到a上来,然后可以发现,把没有作用的能量塔剔除后剩下的能量塔要么是递增的,要么是递减的(考虑到向右传递能量的情况),那么我们就可以用一个栈来保存这些能量塔.

     先从1到n枚举,然后清空栈,然后从n到1枚举,按照上面说的方法把没有用的能量塔剔除掉,直到不能剔除,那么就传递能量,最后记录最大值即可.

如果要枚举求出一个值,如果从其他值去求出这个值不行,那么可以考虑用这个值去更新其它值.

#include <cstdio>
#include <stack>
#include <cstring>
#include <iostream>
#include <algorithm>

using namespace std;

stack<int> s;
int n,h[1000010],v[1000010],ans[1000010];

void push(int x)
{
    while (!s.empty() && h[x] >= h[s.top()])
        s.pop();
    if (!s.empty())
        ans[s.top()] += v[x];
    s.push(x);
}

int main()
{
    scanf("%d", &n);
    for (int i = 1; i <= n; i++)
        scanf("%d%d", &h[i], &v[i]);
    for (int i = 1; i <= n; i++)
        push(i);
    while (!s.empty())
        s.pop();
    for (int i = n; i >= 1; i--)
        push(i);
    int ans1 = 0;
    for (int i = 1; i <= n; i++)
        ans1 = max(ans1, ans[i]);
    printf("%d", ans1);

    return 0;
}

 

posted @ 2016-09-13 22:11  zbtrs  阅读(557)  评论(0编辑  收藏  举报