首先,由于存在2ⁿ⁻¹ 表达式(数字之间的每个n-1 位置上都有两个可能的运算符)并且它们的概率相同,因此期望值是所有表达式的总和除以@987654323 @。所以问题归结为计算表达式的总和。
O(n²) 算法
让x_1, x_2, ..., x_n 成为输入数字。
让S_k 是通过在列表x_1, x_2, ..., x_k 中的每对连续数字之间插入| 或+ 形成的所有表达式的总和。
设N_k 为所有此类表达式的数量。 N_k = 2 ^ (k - 1).
让我们看看如何使用S_1, S_2, ..., S_(k-1) 来计算S_k。
这个想法是将所有可能的表达式除以它们中最后一个"+" 的位置。
-
"... + x_k" 形式的表达式的总和是
-
"... + x_(k-1) | x_k" 形式的表达式的总和是
S_(k-2) + (x_(k-1) | x_k) * N_(k-2)
-
"... + x_(k-2) | x_(k-1) | x_k" 形式的表达式的总和是
S_(k-2) + (x_(k-2) | x_(k-1) | x_k) * N_(k-3)
- ...以此类推,直到单个表达式
x_1 | x_2 | ... | x_k。
这是该算法的 Python 实现。
numbers = [1, 2, 3] # The input numbers.
totals = [0] # The partial sums. For every k > 0 totals[k] is S_k.
for i in range(len(numbers)): # Processing the numbers one by one.
new_total = 0
last_summand = 0 # last_summand is numbers[j] | ... | numbers[i]
for j in range(i, 0, -1): # j is the position of the last plus in the expression.
# On every iteration new_total is increased by the sum of the
# expressions of the form "... + numbers[j] | ... | numbers[i]".
last_summand |= numbers[j]
new_total += totals[j] + last_summand * (2 ** (j - 1))
last_summand |= numbers[0]
new_total += last_summand # Handling the expression with no pluses at all.
totals.append(new_total)
# Now the last element in totals is the sum of all expressions.
print(str(totals[-1]) + '/' + str(2**(len(numbers) - 1)))
进一步优化:O(n*log(M))
这个问题有两个属性可以用来创建一个更快的算法。
- 如果
S_n是由数字x_1, x_2, ..., x_n组成的表达式之和,那么2*S_n是由数字2*x_1, 2*x_2, ..., 2*x_n组成的表达式之和。
- 如果
x_1, x_2, ..., x_n 和y_1, y_2, ..., y_n 是这样的x_k & y_m == 0 对于任何k 和m,并且SX_n 是由x_1, x_2, ..., x_n 形成的表达式的总和,而SY_n 是总和由y_1, y_2, ..., y_n组成的表达式,那么SX_n + SY_n是由x_1+y_1, x_2+y_2, ..., x_n+y_n组成的表达式的总和。
这意味着,问题可以简化为求 1 位数字的表达式之和。从0到31的每个位位置都可以单独处理,找到解决方案后我们可以简单地添加它们。
让x_1, x_2, ..., x_n 是一位数字(每个x_i 是0 或1)。
设S_k 为x_1, x_2, ..., x_k 组成的表达式之和。
设N0_k 为最后一个和等于 0 的此类表达式的数量。
设N1_k 为最后一个和等于 1 的此类表达式的数量。
这是只知道x_k、S_(k-1)、N0_(k-1)和N1_(k-1)的循环关系:
-
k = 1, x_1 = 0:
S_1 = 0
N0_1 = 1
N1_1 = 0
-
k = 1, x_1 = 1:
S_1 = 1
N0_1 = 0
N1_1 = 1
-
k > 1, x_k = 0:
S_k = S_(k-1) * 2
N0_k = N0_(k-1) * 2 + N0_(k-1)
N1_k = N1_(k-1)
-
k > 1, x_k = 1:
S_k = S_(k-1) * 2 + N0_(k-1) * 2 + N0_(k-1)
N0_k = 0
N1_k = N0_(k-1) * 2 + N0_(k-1) * 2
由于S_n可以在O(n)中找到,并且需要对每个位位置找到,因此整个算法的时间复杂度为O(n*log(M)),其中M是数字的上限。
一个实现:
numbers = [1, 2, 3]
max_bits_in_number = 31
def get_bit(x, k):
return (x >> k) & 1
total_sum = 0
for bit_index in range(max_bits_in_number):
bit = get_bit(numbers[0], bit_index)
expression_sum = bit
expression_count = (1 - bit, bit)
for i in range(1, len(numbers)):
bit = get_bit(numbers[i], bit_index)
if bit == 0:
expression_sum = expression_sum * 2
expression_count = (expression_count[0] * 2 + expression_count[1], expression_count[1])
else:
expression_sum = expression_sum * 2 + expression_count[0] * 2 + expression_count[1]
expression_count = (0, expression_count[0] * 2 + expression_count[1]*2)
total_sum += expression_sum * 2**bit_index
print(str(total_sum) + '/' + str(2**(len(numbers) - 1)))