洛谷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; }