[R1E] 过分的子区间
- 难度 普及/提高-
- 时限 1s
- 空限 512m
- 双指针二分
数据规模:,。
思路
「区间内第 小的数 」等价于「区间内小于 的数不足 个」。而区间长度小于 时自动满足该条件,所以两类区间可以统一计数。
对每个左端点 ,区间内小于 的元素个数随右端点 增大而单调不减,因此满足条件(小于 的个数 )的最大右端点 也随 增大而单调不减,用 双指针 扫描:
- 维护指针 和当前区间 中小于 的个数 ;
- 不断右移 ,直到再加入一个小于 的数就会达到 个为止,此时以 为左端点且满足条件的子区间有 个,累加进答案;
- 右移时把 的贡献从 中移除。
复杂度:时间 ,空间 。
仓颉实现
import std.env.*
import std.convert.*
main(): Int64 {
let reader = getStdIn()
let nkx = reader.readln().getOrThrow().split(" ", removeEmpty: true).map({ p => Int64.parse(p) })
let n = nkx[0]
let k = nkx[1]
let x = nkx[2]
let a = reader.readln().getOrThrow().split(" ", removeEmpty: true).map({ p => Int64.parse(p) })
var ans: Int64 = 0
var r: Int64 = -1
var less: Int64 = 0
for (l in 0..n) {
if (r < l - 1) {
r = l - 1
less = 0
}
while (r + 1 < n && less + (if (a[r + 1] < x) { 1 } else { 0 }) < k) {
r += 1
if (a[r] < x) {
less += 1
}
}
ans += r - l + 1
if (l <= r && a[l] < x) {
less -= 1
}
}
println(ans)
return 0
}
要点:
- 条件写成「小于 的个数 」,处理时用
Int64,答案最大为全部 个子区间,不能存进Int32。 - 当 时区间为空,需把 拉回 并把 清零,否则负数会污染计数。