[R39D]购买股票
- 难度 提高
- 时限 1s
- 空限 512m
- 单调栈
对于 的数据,,。
题意
第 天买入后持有到第一个 且 的日子 卖出。对每个 ,求所有「在第 天卖出」的交易利润之和 。
思路
一笔交易 满足: 是 之后第一个比 大的位置。这正是 下一个更大元素(next greater element) 的经典定义。
因此用 单调栈 一次扫描即可解决:
- 维护一个下标栈,栈中下标对应的股价严格递减。
- 从左到右枚举 ,当栈顶 满足 时,说明 就是 的「下一个更大元素」,弹出 ,把利润 累加到 。
- 处理完弹出后,把 入栈。
每个下标至多入栈、出栈各一次,总时间 。
样例验证
:
- :栈空,入栈 。
- :,入栈 。
- :,入栈 。
- :,弹出 ,;,弹出 ,;,入栈 。
- :,弹出 ,;,弹出 ,;入栈 。
得 ,与样例一致。
复杂度
- 时间:,单调栈每个元素进出各一次。
- 空间:,存储价格、答案、栈。
仓颉实现
import std.convert.*
import std.env.*
main(): Int64 {
let reader = getStdIn()
let n = Int64.parse(reader.readln().getOrThrow())
let p = reader.readln().getOrThrow().split(" ", removeEmpty: true).map({ s: String => Int64.parse(s) })
let nn = n
var ans = Array<Int64>(nn, { _ => 0 })
var stk = Array<Int64>(nn, { _ => 0 })
var top: Int64 = 0
var i: Int64 = 0
while (i < nn) {
while (top > 0 && p[stk[top - 1]] < p[i]) {
top = top - 1
let j = stk[top]
ans[i] = ans[i] + (p[i] - p[j])
}
stk[top] = i
top = top + 1
i = i + 1
}
let sb = StringBuilder()
var k: Int64 = 0
while (k < nn) {
if (k > 0) {
sb.append(" ")
}
sb.append(ans[k])
k = k + 1
}
println(sb.toString())
return 0
}