📜  [L,R]范围内两个数字的最大可能按位或(1)

📅  最后修改于: 2023-12-03 14:38:56.738000             🧑  作者: Mango

题目概述

给定一个区间 $[L,R]$,求区间内任意两个数按位或的最大值。

解题思路

由于按位或的转移是 $1$ 转移成 $1$,$0$ 转移成 $1$ 或 $0$,因此一个数 $k$ 选不选,只会对所有二进制下第 $i$ 位上的值为 $1$ 的数产生影响。也就是说,对于一个数的决策,我们只需要考虑这个数在二进制下的那些位上是 $1$ 的情况,而对于那些位为 $0$ 的情况,我们无论如何都不会选。

因此,我们可以考虑用状压 DP 的方式来解决此类问题,设 $f_{i,S}$ 表示考虑前 $i$ 个数,其中已选数的按位或的结果为 $S$ 的最大值。转移方程为:

$$ f_{i,S \operatorname{or} x_i} = \max {f_{i-1,S} \operatorname{or} x_i,x_i} $$

其中 $x_i$ 表示第 $i$ 个数。边界条件为 $f_{0,0} = 0$。最终的答案为 $\max\limits_{S=0}^V f_{n,S}$,其中 $V$ 表示所有数的按位或的最大值。

代码实现
def solve(L, R):
    lst = []
    for k in range(30, -1, -1):
        if (L >> k) & 1 != (R >> k) & 1:
            lst.append(k)
    n = len(lst)
    if n == 0:
        return R
    f = [0] * (1 << n)
    f[0] = L
    for i in range(1, n + 1):
        x = (L >> lst[i - 1]) & 1
        mask = (1 << i) - 1
        for j in range(mask, -1, -1):
            if (j >> (i - 1)) & 1:
                f[j] = max(f[j], (f[j & (mask ^ (1 << (i - 1)))] << 1) + x)
            else:
                f[j] = max(f[j], f[j & (mask ^ (1 << (i - 1)))])
    ans = 0
    for j in range(1, 1 << n):
        ans = max(ans, f[j] | (R & ((1 << lst[j.bit_length() - 1]) - 1)))
    return ans
参考资料