[R63E] 这是一个01串题2
- 难度 普及+/提高
- 时限 1s
- 空限 512m
- 贪心前缀和
数据规模:,。
思路
把字符 0 翻成 1 只会让字典序变大,且对消除相邻的 1 毫无帮助,因此最优方案的每次翻转一定把某个 1 翻成 0;而把 1 翻成 0 永远不会破坏「不存在相邻 1」的性质。问题等价于:从 中选出至多 个位置(必须是 1)翻成 0,使剩余字符串无相邻 1,且字典序最小。
考虑一段连续的 1,设其长度为 ,至少要翻 个位置才能断开所有相邻对。在最小翻转过数下,为保证字典序最小,翻法唯一确定:
- 为偶数:翻段内奇数偏移位,如 ;
- 为奇数:翻段内偶数偏移位,如 。
各段互不影响,记最少操作总数为 。若 ,无法得到合法串,输出 -1。
当 时,先做这 次翻转得到串 。多余的操作次数越多,字典序越小,因此每次多余操作都把 中最靠左的 1 翻成 0。设多余操作次数为 ,若 不小于 中 1 的总数 ,则 为全 0 串,任何询问答案都是 0;否则记 为 中从左往右第 个 1 的位置( 时令 ),那么 中位置 处全部为 0,位置 处与 完全一致。
因此询问 的答案就是 的 1 在区间 中的个数,用 的前缀和 计算即可;若 则答案为 0。
复杂度
预处理扫描一次 ,每次询问 ,总复杂度 。
仓颉实现
import std.env.*
import std.convert.*
import std.collection.*
func solve(reader: ConsoleReader): Unit {
let nq = reader.readln().getOrThrow().split(" ", removeEmpty: true).map({ p: String => Int64.parse(p) })
let n = nq[0]
let qnum = nq[1]
let s = reader.readln().getOrThrow()
let chars = s.toRuneArray()
let isOne = Array<Int64>(n, { _ => 0 })
let kept = ArrayList<Int64>()
var need: Int64 = 0
var i: Int64 = 0
while (i < n) {
if (chars[i] == r'1') {
let st = i
while (i < n && chars[i] == r'1') {
i += 1
}
let en = i - 1
let len = en - st + 1
if (len % 2 == 0) {
var j = st
while (j <= en) {
need += 1
j += 2
}
j = st + 1
while (j <= en) {
isOne[j] = 1
kept.add(j + 1)
j += 2
}
} else {
var j = st + 1
while (j <= en) {
need += 1
j += 2
}
j = st
while (j <= en) {
isOne[j] = 1
kept.add(j + 1)
j += 2
}
}
} else {
i += 1
}
}
let pref = Array<Int64>(n + 1, { _ => 0 })
var acc: Int64 = 0
var j: Int64 = 1
while (j <= n) {
acc += isOne[j - 1]
pref[j] = acc
j += 1
}
let m = kept.size
var q: Int64 = 0
while (q < qnum) {
let qs = reader.readln().getOrThrow().split(" ", removeEmpty: true).map({ p: String => Int64.parse(p) })
let k = qs[0]
let l = qs[1]
let r = qs[2]
if (k < need) {
println("-1")
} else {
let e = k - need
if (e >= m) {
println("0")
} else {
var p: Int64 = 0
if (e > 0) {
p = kept.get(e - 1).getOrThrow()
}
if (r <= p) {
println("0")
} else {
var left = l - 1
if (p > left) {
left = p
}
let ans = pref[r] - pref[left]
println(ans.toString())
}
}
}
q += 1
}
}
main(): Int64 {
let reader = getStdIn()
solve(reader)
return 0
}