[R59E] 01序列
- 难度 中等
- 时限 1s
- 空限 512m
- 前缀和组合计数
数据规模:。
思路
一个 0110 子序列由四个位置 构成,满足 。某个连续子串 包含这四元组,当且仅当 且 : 有 种选法(), 有 种选法()。因此答案等于所有合法四元组的 之和。
从左到右扫描 (位置从 起),维护三个量:
- :已扫描的 的位置之和,即 ;
- :所有满足 、、 的二元组的 之和;
- :所有满足 、、 的三元组的 之和,其中 取已扫描到的位置。
扫描到位置 时:
- 若 :以 作为四元组的 ,贡献为 ,累加进答案;随后 ;
- 若 :先执行 (把 当作 , 只能取 之前的 ),再执行 (把 当作 , 取 之前的 )。顺序不能颠倒。
与 始终对 取模即可。
复杂度:时间 ,空间 。
仓颉实现
import std.env.*
import std.convert.*
main(): Int64 {
let reader = getStdIn()
let n = Int64.parse(reader.readln().getOrThrow())
let s = reader.readln().getOrThrow()
let arr = s.toRuneArray()
let MOD: Int64 = 998244353
// zsum: 已扫描的 0 的位置(1 起下标)之和
// jsum: 所有 (0 的位置 i, 1 的位置 j),i < j 的 i 之和
// ab: 所有满足 i < j < k 且 S[i]=0、S[j]=S[k]=1 的三元组的 i 之和
var zsum: Int64 = 0
var jsum: Int64 = 0
var ab: Int64 = 0
var ans: Int64 = 0
for (p in 0..n) {
if (arr[p] == r'0') {
ans = (ans + ab * (n - p)) % MOD
zsum += p + 1
} else {
ab = (ab + jsum) % MOD
jsum = (jsum + zsum) % MOD
}
}
println(ans)
return 0
}