zoukankan      html  css  js  c++  java
  • 洛谷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;
    }
  • 相关阅读:
    Path Sum
    Intersection of Two Linked Lists (求两个单链表的相交结点)
    Nginx入门资料
    赛马问题
    翻转单词顺序 VS 左旋转字符串
    重建二叉树
    Fibonacci相关问题
    Find Minimum in Rotated Sorted Array(旋转数组的最小数字)
    常用查找算法总结
    Contains Duplicate
  • 原文地址:https://www.cnblogs.com/zbtrs/p/5869978.html
Copyright © 2011-2022 走看看