[R72D] 过滤
数据规模:,。
思路
只看一对对称位置 ,不妨设 。由 的定义:
- 时,两边都大于 , 均为 ,配对相等;
- 时,只有一边满足 , 不相等;
- 时,两边都不大于 , 均为 ,配对相等。
因此这一对位置恰好使阈值区间 非法;若 ,则对任意阈值都相等。对每对对称位置取 、,当 时用差分数组把区间 加一。
最后对差分数组做前缀和,覆盖次数为 的阈值 就是使 为回文数组的答案(覆盖次数即该阈值下的失配对数)。
复杂度
时间 ,空间 。
仓颉实现
查看仓颉实现
import std.env.*
import std.convert.*
main() {
let reader = getStdIn()
let n = Int64.parse(reader.readln().getOrThrow())
let nn = n
let a = reader.readln().getOrThrow().split(" ", removeEmpty: true).map({ p: String => Int64.parse(p) })
// 差分数组按值 1..n 建立,大小 n+2,下标 0..n+1
let diff = Array<Int64>(nn + 2, { _ => 0 })
var i = 0
while (i < (nn + 1) / 2) {
let u = a[i]
let v = a[nn - 1 - i]
var l = u
var r = v
if (l > r) {
l = v
r = u
}
if (l < r) {
diff[l] += 1
diff[r] -= 1
}
i += 1
}
// 前缀和:覆盖次数为 0 的阈值 x 即为答案,先数出个数 k
var k: Int64 = 0
var cur: Int64 = 0
i = 1
while (i <= nn) {
cur += diff[i]
if (cur == 0) {
k += 1
}
i += 1
}
println(k)
// 第二遍扫描直接输出合法阈值,空格分隔,行尾换行
var sep = ""
cur = 0
i = 1
while (i <= nn) {
cur += diff[i]
if (cur == 0) {
print(sep)
print(i)
sep = " "
}
i += 1
}
println()
}