📅  最后修改于: 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