[R79F] 展品
数据规模:,。
思路
区间是否合法关于右端点单调。 固定 ,若 非法(内部能选出 交错模式),则任何 的 也非法。设 为所有末下标 的非法四元组的首下标 的最大值(没有则为 ),那么 合法当且仅当 ,答案为
把四元组按第三元 参数化。 记 为 上一次出现的位置(没有则为 )。考察所有以 为第三元的合法四元组 ,其中 ,。由于 是 之前最后一个 的出现位置,必有 。
- 若 ,则 出现在 内,取 起始更优;
- 若 ,由 且 、 都是 ,把第三元换成 后 仍是合法四元组,起始不会变小。第三元严格下降且始终大于 ,反复替换必终止。
因此 只需考察 的四元组。此时 必须落在 内, 是某个 在 之后的第一次出现。对每个 只保留起始最大者,其最小末下标为
取到最小值的 满足 ,即 在 内出现过,对应 。条件 同时保证 (否则 是 内的 ,与 、 相邻矛盾),故 是合法四元组。
扫描求所有 。 把 从 到 递增扫描,给所有尚未赋值且满足
的 定下 。 递增保证了取到的是「首个满足条件的位置」,每个 恰好被赋值一次。这相当于维护一个以 值为关键字的集合,支持「把区间 内所有关键字 的元素取出」。用线段树维护区间最小值即可:从根递归,若区间最小值 则剪枝,否则下传;到达叶子即取出(置为 )并记录 。每个位置只被取一次,总复杂度 。
随后按 扫描,维护 并累加 ,即得答案。
复杂度
时间 ,空间 。
仓颉实现
查看仓颉实现
import std.convert.*
import std.env.*
var gdata = Array<Byte>(0, { _ => 0 })
var gpos: Int64 = 0
func nextInt(): Int64 {
while (gpos < gdata.size && Int64(gdata[gpos]) <= 32) { gpos += 1 }
var x: Int64 = 0
while (gpos < gdata.size && Int64(gdata[gpos]) > 32) {
x = x * 10 + Int64(gdata[gpos]) - 48
gpos += 1
}
return x
}
var gs = Array<Int64>(0, { _ => 0 })
var gmn = Array<Int64>(0, { _ => 0 })
var gINF: Int64 = 0
var gLo: Int64 = 0
var gHi: Int64 = 0
var gTh: Int64 = 0
var gBest: Int64 = 0
func extract(node: Int64, l: Int64, r: Int64): Unit {
if (r < gLo || l > gHi || gmn[node] >= gTh) {
return
}
if (l == r) {
if (gs[l] > gBest) {
gBest = gs[l]
}
gmn[node] = gINF
return
}
let mid = (l + r) / 2
extract(node * 2, l, mid)
extract(node * 2 + 1, mid + 1, r)
let lv = gmn[node * 2]
let rv = gmn[node * 2 + 1]
gmn[node] = if (lv < rv) { lv } else { rv }
}
func build(node: Int64, l: Int64, r: Int64): Unit {
if (l == r) {
gmn[node] = gs[l]
return
}
let mid = (l + r) / 2
build(node * 2, l, mid)
build(node * 2 + 1, mid + 1, r)
let lv = gmn[node * 2]
let rv = gmn[node * 2 + 1]
gmn[node] = if (lv < rv) { lv } else { rv }
}
main() {
gdata = getStdIn().readToEnd().getOrThrow().toArray()
let n = nextInt()
gINF = n + 5
var a = Array<Int64>(n + 1, { _ => 0 })
for (i in 1..=n) {
a[i] = nextInt()
}
let nn = n
gs = Array<Int64>(nn + 1, { _ => 0 })
gmn = Array<Int64>(4 * nn + 10, { _ => 0 })
var last = Array<Int64>(nn + 2, { _ => 0 })
for (k in 1..=n) {
let v = a[k]
gs[k] = last[v]
last[v] = k
}
if (n >= 1) {
build(1, 1, nn)
var M: Int64 = 0
var ans: Int64 = 0
for (p in 1..=n) {
gLo = gs[p] + 1
gHi = p - 1
gTh = gs[p]
gBest = 0
if (gLo <= gHi) {
extract(1, 1, nn)
}
if (gBest > M) {
M = gBest
}
ans += p - M
}
println(ans)
}
}