[R78F] 归零
数据规模:,,。
思路
设前缀和 ()。关键观察:计数器从 出发依次读取 后,最终读数为
对长度归纳即证:设处理到 时 ,其中 ,则
正好是把 纳入最小值后的结果。
令 ,问题转化为:统计满足 且
的下标对 个数。
固定右端点 ,记 。区间 上的最小值恰好等于 ,当且仅当同时满足:
- 区间内没有小于 的值,即 要大于最后一个满足 的下标 ;
- 区间内有等于 的值,即 不超过最后一个满足 的下标 。
因此合法的 恰好是整数区间
贡献为 个。
接下来只需对每个 快速求 与 。把所有前缀和离散化,扫描 的同时维护「每个取值最后一次出现的下标」:
- :值域上小于 的所有位置中最后下标的最大值,用树状数组维护下标最大值,做前缀查询;
- :直接用一个数组记录每个离散值最后出现的下标。
实现上先把 插入数据结构再查询 :由于 ,它不会干扰「小于 」的查询;而 时 ,恰好使 自动成立,无需特判。
复杂度
离散化排序 ,每个 一次树状数组更新、一次前缀查询与常数次二分,共 ;空间 。
答案最大为 ,需要用 Int64 存放。
仓颉实现
查看仓颉实现
import std.env.*
import std.sort.*
var gdata = Array<Byte>(0, { _ => 0 })
var gpos: Int64 = 0
var glen: Int64 = 0
func nextInt(): Int64 {
while (gpos < glen && Int64(gdata[gpos]) <= 32) {
gpos += 1
}
var sign: Int64 = 1
if (gpos < glen && Int64(gdata[gpos]) == 45) {
sign = -1
gpos += 1
}
var x: Int64 = 0
while (gpos < glen && Int64(gdata[gpos]) > 32) {
x = x * 10 + Int64(gdata[gpos]) - 48
gpos += 1
}
return x * sign
}
func lowerBound(a: Array<Int64>, x: Int64): Int64 {
var left: Int64 = 0
var right = a.size
while (left < right) {
let mid = (left + right) / 2
if (a[mid] < x) {
left = mid + 1
} else {
right = mid
}
}
return left
}
func bitUpdate(bit: Array<Int64>, size: Int64, pos0: Int64, v: Int64): Unit {
var pos = pos0
while (pos <= size) {
if (v > bit[pos]) {
bit[pos] = v
}
pos += pos & (-pos)
}
}
func bitQuery(bit: Array<Int64>, pos0: Int64): Int64 {
var pos = pos0
var res: Int64 = -1
while (pos > 0) {
if (bit[pos] > res) {
res = bit[pos]
}
pos -= pos & (-pos)
}
return res
}
main() {
let reader = getStdIn()
gdata = reader.readToEnd().getOrThrow().toArray()
glen = gdata.size
let n = nextInt()
let k = nextInt()
let s = Array<Int64>(n + 1, { _ => 0 })
for (i in 1..=n) {
s[i] = s[i - 1] + nextInt()
}
let vals = Array<Int64>(n + 1, { i: Int64 => s[i] })
sort(vals)
let size = vals.size
let bit = Array<Int64>(size + 1, { _ => -1 })
let lastEq = Array<Int64>(size + 1, { _ => -1 })
var ans: Int64 = 0
let c0 = lowerBound(vals, s[0]) + 1
bitUpdate(bit, size, c0, 0)
lastEq[c0] = 0
for (r in 1..=n) {
let c = lowerBound(vals, s[r]) + 1
bitUpdate(bit, size, c, r)
lastEq[c] = r
// 需要 min_{t in [j, r]} s_t = s[r] - k
let target = s[r] - k
let lb = lowerBound(vals, target)
let q = bitQuery(bit, lb)
var v: Int64 = -1
if (lb < size && vals[lb] == target) {
v = lastEq[lb + 1]
}
if (v >= 0) {
var hi = v
if (hi > r - 1) {
hi = r - 1
}
let lo = q + 1
if (hi >= lo) {
ans += hi - lo + 1
}
}
}
println(ans)
}