CF1327F AND Segments 题解
提示 1
每个比特位分别计算方案数,最后答案为每个比特位的方案数的乘积。
现在来思考
提示 2
对于每个约束:
- 如果
x (在这个比特位上)是0 ,意味着区间[l,r] 至少要有一个0 。 - 如果
x (在这个比特位上)是1 ,意味着区间[l,r] 必须都是1 。
提示 3
考虑哪些位置填入
定义
如果下标
否则,枚举上一个
由于有「区间
特别地,我们规定
现在需要思考的问题是,对于每个
提示 4
讨论
- 如果
i-1 恰好是某个约束区间[l,r] 的右端点,且这个区间至少要有一个0 ,那么转移来源不能小于l ,否则从l 到r 就都是1 了。当然,转移来源也不能小于f[i-1] 对应的\textit{minJ} ,因为左边的其它约束区间也要满足。 - 如果
i-1 不是某个约束区间[l,r] 的右端点,那么f[i] 对应的\textit{minJ} 和f[i-1] 对应的\textit{minJ} 是一样的。
我们可以预处理数组
提示 5
如何快速计算
注意到
如何快速知道下标
用差分数组标记必须全为
package main
import("bufio";."fmt";"os")
func max(a, b int) int { if b > a { return b }; return a }
func main() {
in := bufio.NewReader(os.Stdin)
const mod = 998244353
var n, k, m int
Fscan(in, &n, &k, &m)
cons := make([]struct{ l, r, x int }, m)
for i := range cons {
Fscan(in, &cons[i].l, &cons[i].r, &cons[i].x)
}
ans := 1
f := make([]int, n+2)
f[0] = 1
for b := 0; b < k; b++ {
maxL := make([]int, n+1)
d := make([]int, n+2)
for _, p := range cons {
if p.x>>b&1 == 0 {
maxL[p.r] = max(maxL[p.r], p.l)
} else {
d[p.l]++
d[p.r+1]--
}
}
sumF := 1
sumD := 0
left := 0
for i := 1; i <= n+1; i++ {
for left < maxL[i-1] {
sumF -= f[left]
left++
}
sumD += d[i]
if sumD > 0 {
f[i] = 0
continue
}
sumF %= mod
f[i] = sumF
sumF *= 2
}
// f[n+1] 相当于枚举最后一个 0 的下标,计算这些 f[i] 之和
ans = ans * f[n+1] % mod
}
Print((ans%mod + mod) % mod) // 保证答案非负
}
- 时间复杂度:
\mathcal{O}(k\cdot(n+m)) 。