[R63C] 这是一个01串题1
- 难度 普及
- 时限 1s
- 空限 512m
- 贪心差分数组
数据规模:, 和 仅包含字符
0和1。
思路
先构造差异数组: 当且仅当 ,否则 。
原问题等价于:在 上每次选择一个区间并把其中的所有值翻转,求把 变为全 的最少操作次数。
如果某次翻转的区间里含有 0,这些 0 会被翻成 1,相当于凭空创造出新的差异段,不会让总操作数更优。因此每次操作恰好翻转一段连续的 1 总是最优的:这样一段连续的 1 一次操作就能整体清零。
于是最少操作次数就等于 中连续 1 的段数。只需遍历一遍,每当遇到一个差异位且它前一位不是差异位时,就开启了一段新的连续 1,计数加一即可。
时间复杂度 ,空间复杂度 。
仓颉实现
import std.env.*
import std.convert.*
main(): Int64 {
let reader = getStdIn()
let n = Int64.parse(reader.readln().getOrThrow())
let s = reader.readln().getOrThrow().toRuneArray()
let t = reader.readln().getOrThrow().toRuneArray()
var ans = 0
var i = Int64(0)
while (i < n) {
if (s[i] != t[i]) {
// 进入一段新的连续 1,计数一次并跳过整段
ans = ans + 1
while (i < n && s[i] != t[i]) {
i = i + 1
}
} else {
i = i + 1
}
}
println(ans)
return 0
}
要点
- 核心转化:用差异数组 把「翻转 的区间使 」归约为「翻转 的区间使 清零」。
- 贪心最优:翻转区间内含
0只会创造新差异段,所以最优操作恰好一段一段地翻转连续的1,答案就是连续1的段数。 - 计数技巧:只需统计「当前位是差异位、上一位不是差异位」的位置个数,无需显式建出差分数组。