题目复现
题目:P1901 发射站 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
这个题目理解的不是很清楚,我们画个图来理解一下:
塔1比塔2低,那么塔2就是塔1的最近的比他高的一座塔,它会把塔1的发射能量接收到。
塔2比塔1高,它向左发射的能量每人接收,但是向右有塔3可以接收到。
典型:这里塔5比塔4、塔6高,所以它的发射能量会被塔3(左最近高于塔5)和塔7(右最近高于塔5)给接收
典型:塔3的能量只会被塔8接收,因为塔8是塔3向右最近的比它高的塔,而塔3向左没有塔比它高,所以塔3的能量向右没有塔可以接收
题解
我们先朴素的这么想:分别模拟所有塔的左右发射能量传播与接收,举例塔3
塔3向右传播,如果是维护一个单调栈,显然塔4是应该进栈的,不然有什么好维护的(不然就是双循环找最近最高塔了),那么我们可以确定一件事,进栈的塔比栈里的塔低。
塔5高于塔4低于塔3,塔4出栈,塔5进栈,则塔5要接收到塔4的发射能量。
塔6低于塔5,进栈。
塔7高于塔6、塔5,塔6先出栈,塔7接收塔6发射能量,塔5出栈,塔7接收塔5的发射能量。
塔8高于塔7、塔3,塔7出栈,塔8接收塔7,塔3出栈,塔8接收塔3。
塔8再向右没有东西了,结束向右传播。
可以看出,上面一次单调栈维护(O(n))就完成了所有塔向一个方向传播的最近最高能量接收。
但只往右一次,塔3还可以接收到塔4的能量,这是往左的,就没计算到,所以我们理应往左也传播一次。
但是实际上不用,应为入栈时,栈内的塔都比入栈塔高或者栈空了入栈的最高,若栈没空,那么入栈前的栈顶塔就是入栈塔的左传播的最近最高塔,那么只要让该塔可以接收到入栈塔的发射能量就可以完成向左传播的能量接收模拟。
我们维护一个单调栈即可。我们维护栈中的发射站高度的单调性。
栈中储存发射站的标号。我们将接收能量的过程分成两个阶段:
1.入栈时,由于栈是具有单调性的,如果栈顶的元素没有新加进来的元素高,那么他肯定就不能给后面的元素传输能量了,我们退掉这个元素,将新的元素加进来即可。
2.新的元素加进来以后,会对他在栈中下面那个元素传输能量,也就是离他最近还高于他的那个。
伪代码
for{
读入新元素
while(栈非空&&新元素高度大于栈顶元素高度){
新元素能量加上栈顶元素能量,退栈;
}
栈顶元素能量加上新元素能量(对应第二种情况);
将新元素加入栈中;
}
代码1
def Solution():
N = int(input())
h, v = [0]*(N+1), [0]*(N+1)
top = 1
stack = [0] * (N+1)
sumn = [0]*(N+1)
for i in range(1,N+1):
h[i], v[i] = map(int, input().split())
while top and h[stack[top]] < h[i]:
sumn[i] += v[stack[top]]
top -= 1
sumn[stack[top]] += v[i]
top += 1
stack[top] = i
return max(sumn[1:])
print(Solution())
代码2
def Solution2():
N = int(input())
hv = []
for i in range(N):
hv.append(tuple(map(int, input().split())))
# stack单调栈记录的是idx
stack = []
sumn = [0] * N
# 向右遍历一次维护单调栈即可同时完成向右向左的能量接收计算
for i in range(N):
while stack and hv[stack[-1]][0] < hv[i][0]:
sumn[i] += hv[stack.pop()][1]
if stack:
sumn[stack[-1]] += hv[i][1]
stack.append(i)
else:
stack.append(i)
return max(sumn)
print(Solution2())
代码不能全部AC,会有TLE限制,可能是洛谷对Python不太友好吧。哈哈哈。洛谷和leetcode真的是没的比。