有多少组 4 个数的异或等于 0?
How many sets of 4 numbers are there such that their xor is equal to 0?
我有两个非负整数 x 和 y,它们都最多有 30 位(因此它们的值大约为 10^9)。
我想计算有多少组 4 个数字 {a_1、a_2、a_3、a_4} 使得 a_1 + a_2 = x 和 a_3 + a_4 = y 并且所有这 4 个数字的 xor 等于 0。
解决这个问题最快的算法是什么?
我能想到的最快的方法是将 xor 方程重新排列为 a_1 xor a_2 = a_3 xor a_4。
然后我可以在O(x) 中计算左侧的所有值,在O(y) 中计算右侧的值,因此整个算法在O(x + y) 中运行。
设N(x, y)
为本题的解数。显然 N(0, 0)
是 1,因为唯一的解决方案是 (0, 0, 0, 0)。如果 x
或 y
为负,则无解,因为我们要求 a1、a2、a3、a4 均为非负。
否则,我们可以从求解最低位开始,生成递归关系。让我们写 n:0
和 n:1
来表示 2n+0 和 2n+1(所以 0 和 1 是最低位)。
然后:
N(0, 0) = 1
N(-x, y) = N(x, -y) = 0
N(x:0, y:0) = N(x, y) + N(x-1, y) + N(x, y-1) + N(x-1, y-1)
N(x:0, y:1) = N(x:1, y:0) = 0
N(x:1, y:1) = 4 * N(x, y)
要看到这些,必须考虑任何 a1、a2、a3、a4 可能的低位。
首先N(x:0, y:0)
。我们需要 a1+a2 的低位为 0,这意味着 a1 和 a2 要么都是偶数,要么都是奇数。如果它们都是奇数,则有一个进位,并且高位加 1 的总和必须等于 x 的高位。同样的逻辑适用于 a3、a4。有4种可能:a1、a2、a3、a4的低位全为0,a1、a2的低位为1,a3、a4的低位为1,a1、a2、a3、a4的低位为1。即4 例。
其次N(x:0, y:1)
和N(x:1, y:0)
。如果一个和是偶数,另一个是奇数,则没有解决方案:可以检查每个组合的 a1、a2、a3、a4 的最低位以找出答案。
第三N(x:1, y:1)
。恰好 a1 和 a2 中的一个必须是奇数,并且类似地恰好 a3 和 a4 中的一个必须是奇数。这有 4 种可能性,并且在任何情况下都没有进位。
这是一个完整的解决方案:
def N(x, y):
if x == y == 0: return 1
if x < 0 or y < 0: return 0
if x % 2 == y % 2 == 0:
return N(x//2, y//2) + N(x//2-1, y//2) + N(x//2, y//2-1) + N(x//2-1, y//2-1)
elif x % 2 == y % 2 == 1:
return 4 * N(x//2, y//2)
else:
return 0
该算法进行多次递归调用,理论上是指数级的。但在实践中,许多分支很快终止,因此代码运行速度足够快,足以处理高达 2^30 的值。但是当然,你可以添加缓存或者使用动态规划table来保证O(log(x)+log(y)).
的运行时间
最后,为了提高正确性的可信度,这里有一些针对原始 O(xy) 解决方案的测试:
def N_slow(x, y):
s = 0
for a1 in xrange(x + 1):
for a3 in xrange(y + 1):
a2 = x - a1
a4 = y - a3
if a1 ^ a2 ^ a3 ^ a4:
continue
s += 1
return s
for x in xrange(50):
for y in xrange(50):
n = N(x, y)
ns = N_slow(x, y)
if n != ns:
print 'N(%d, %d) = %d, want %d' % (x, y, n, ns)
我有两个非负整数 x 和 y,它们都最多有 30 位(因此它们的值大约为 10^9)。
我想计算有多少组 4 个数字 {a_1、a_2、a_3、a_4} 使得 a_1 + a_2 = x 和 a_3 + a_4 = y 并且所有这 4 个数字的 xor 等于 0。
解决这个问题最快的算法是什么?
我能想到的最快的方法是将 xor 方程重新排列为 a_1 xor a_2 = a_3 xor a_4。
然后我可以在O(x) 中计算左侧的所有值,在O(y) 中计算右侧的值,因此整个算法在O(x + y) 中运行。
设N(x, y)
为本题的解数。显然 N(0, 0)
是 1,因为唯一的解决方案是 (0, 0, 0, 0)。如果 x
或 y
为负,则无解,因为我们要求 a1、a2、a3、a4 均为非负。
否则,我们可以从求解最低位开始,生成递归关系。让我们写 n:0
和 n:1
来表示 2n+0 和 2n+1(所以 0 和 1 是最低位)。
然后:
N(0, 0) = 1
N(-x, y) = N(x, -y) = 0
N(x:0, y:0) = N(x, y) + N(x-1, y) + N(x, y-1) + N(x-1, y-1)
N(x:0, y:1) = N(x:1, y:0) = 0
N(x:1, y:1) = 4 * N(x, y)
要看到这些,必须考虑任何 a1、a2、a3、a4 可能的低位。
首先N(x:0, y:0)
。我们需要 a1+a2 的低位为 0,这意味着 a1 和 a2 要么都是偶数,要么都是奇数。如果它们都是奇数,则有一个进位,并且高位加 1 的总和必须等于 x 的高位。同样的逻辑适用于 a3、a4。有4种可能:a1、a2、a3、a4的低位全为0,a1、a2的低位为1,a3、a4的低位为1,a1、a2、a3、a4的低位为1。即4 例。
其次N(x:0, y:1)
和N(x:1, y:0)
。如果一个和是偶数,另一个是奇数,则没有解决方案:可以检查每个组合的 a1、a2、a3、a4 的最低位以找出答案。
第三N(x:1, y:1)
。恰好 a1 和 a2 中的一个必须是奇数,并且类似地恰好 a3 和 a4 中的一个必须是奇数。这有 4 种可能性,并且在任何情况下都没有进位。
这是一个完整的解决方案:
def N(x, y):
if x == y == 0: return 1
if x < 0 or y < 0: return 0
if x % 2 == y % 2 == 0:
return N(x//2, y//2) + N(x//2-1, y//2) + N(x//2, y//2-1) + N(x//2-1, y//2-1)
elif x % 2 == y % 2 == 1:
return 4 * N(x//2, y//2)
else:
return 0
该算法进行多次递归调用,理论上是指数级的。但在实践中,许多分支很快终止,因此代码运行速度足够快,足以处理高达 2^30 的值。但是当然,你可以添加缓存或者使用动态规划table来保证O(log(x)+log(y)).
的运行时间最后,为了提高正确性的可信度,这里有一些针对原始 O(xy) 解决方案的测试:
def N_slow(x, y):
s = 0
for a1 in xrange(x + 1):
for a3 in xrange(y + 1):
a2 = x - a1
a4 = y - a3
if a1 ^ a2 ^ a3 ^ a4:
continue
s += 1
return s
for x in xrange(50):
for y in xrange(50):
n = N(x, y)
ns = N_slow(x, y)
if n != ns:
print 'N(%d, %d) = %d, want %d' % (x, y, n, ns)