CF1665E MinimizOR 题解
从特殊到一般。
一
如果
如果有两个
相当于只需要知道最小的两个数是多少,就能确定 OR 最小是多少。
二
如果
考虑下面这三个二进制数,其中
如果只选择
只选择
猜想:在
证明:分类讨论。
- 如果有两个
0? ,那么 OR 的最高位肯定是0 ,问题变成一个比特,也就是a 中只有0 和1 的情况。我们已经知道,这只需要知道最小的2 个数。 - 如果没有
0? 只有1? ,那么 OR 的最高位肯定是1 ,所以同上,变成一个比特的问题,也只需要知道最小的2 个数。 - 如果恰好有一个
0? ,其余的是1? ,继续分类讨论:- 如果
0? 和1? 的 OR 最小,那么1? 这边只需要选最小的数。 - 如果
1? 和1? 的 OR 最小,问题变成上面讨论的第 2 点,需要知道1? 中最小的2 个数。 - 所以知道最小的
3 个数就行,OR 的最小值一定是这3 个数中的2 个数的 OR。
- 如果
三
如果
至少要知道最小的
按照如下方式构造,可以使 OR 的最小值一定来自第三小和第四小的数的 OR。
如果
四
总的来说,通过数学归纳法可以证明,OR 的最小值一定是最小的
所以用线段树维护区间内最小的
package main
import ("bufio";."fmt";"os")
func min(a, b int) int { if b < a { return b }; return a }
type seg [][]int
// 合并两个有序数组,保留前 k 个数
func merge(a, b []int) []int {
const k = 31
i, n := 0, len(a)
j, m := 0, len(b)
res := make([]int, 0, min(n+m, k))
for len(res) < k {
if i == n {
res = append(res, b[j:min(j+k-len(res), m)]...)
break
}
if j == m {
res = append(res, a[i:min(i+k-len(res), n)]...)
break
}
if a[i] < b[j] {
res = append(res, a[i])
i++
} else {
res = append(res, b[j])
j++
}
}
return res
}
func (t seg) build(a []int, o, l, r int) {
if l == r {
t[o] = a[l-1 : l]
return
}
m := (l + r) >> 1
t.build(a, o<<1, l, m)
t.build(a, o<<1|1, m+1, r)
t[o] = merge(t[o<<1], t[o<<1|1])
}
func (t seg) query(o, l, r, L, R int) []int {
if L <= l && r <= R {
return t[o]
}
m := (l + r) >> 1
if R <= m {
return t.query(o<<1, l, m, L, R)
}
if m < L {
return t.query(o<<1|1, m+1, r, L, R)
}
return merge(t.query(o<<1, l, m, L, R), t.query(o<<1|1, m+1, r, L, R))
}
func main() {
in := bufio.NewReader(os.Stdin)
out := bufio.NewWriter(os.Stdout)
defer out.Flush()
var T, n, q, l, r int
for Fscan(in, &T); T > 0; T-- {
Fscan(in, &n)
a := make([]int, n)
for i := range a {
Fscan(in, &a[i])
}
t := make(seg, n*4)
t.build(a, 1, 1, n)
for Fscan(in, &q); q > 0; q-- {
Fscan(in, &l, &r)
b := t.query(1, 1, n, l, r)
ans := 1 << 30
for i, v := range b {
for _, w := range b[:i] {
ans = min(ans, v|w)
}
}
Fprintln(out, ans)
}
}
}
时间复杂度:
空间复杂度: