有多少组 4 个数字使得它们的异或等于 0?

use*_*235 3 algorithm dynamic-programming xor combinatorics bitwise-xor

我有两个非负整数 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 个数字的异或等于 0。

解决这个问题最快的算法是什么?

我能想到的最快的方法是将异或方程重新排列为a_1 xor a_2 = a_3 xor a_4。

然后我可以在 O(x) 中计算左侧的所有值,在 O(y) 中计算右侧的所有值,因此整个算法在 O(x + y) 中运行。

Pau*_*kin 5

N(x, y)为该问题的解数。显然N(0, 0)是 1,因为唯一的解是 (0, 0, 0, 0)。如果 或xy负数,则无解,因为我们要求 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)
Run Code Online (Sandbox Code Playgroud)

要看到这些,必须考虑任何 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
Run Code Online (Sandbox Code Playgroud)

该算法进行多次递归调用,因此理论上是指数级的。但实际上,许多分支很快终止,因此对于高达 2^30 的值,代码运行得足够快。当然,您可以添加缓存或使用动态规划表来保证 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)
Run Code Online (Sandbox Code Playgroud)