如何以P/Q
鉴于:
N个整数
2个运营商,'按位OR' &安培; ' +'
我们可以使用两个运算符中的任何一个,在每个连续的整数之间具有相等的概率来形成表达式。
目前,我想到的解决方案是使用运算符生成所有可能的表达式,然后使用每个表达式的值,我可以计算它的预期值。
但随着N的增长,这种方法失败了。还有其他方法可以在时间复杂度方面有效吗?
注意:对于这个问题:'按位OR'优先于' +'操作
最多可以有10 ^ 5个整数。
示例:
Input
1 2 3
Output
19/4
不同的方式是:
1+2+3 = 6
1+2|3 = 4
1|2+3 = 6
1|2|3 = 3
所有这些方式都有概率= 1/4
因此预期值为19/4
答案 0 :(得分:0)
重要的观察是每个+
将其左右部分分成可以独立处理的部分。
让数组为a[1…N]
。将f(i)
定义为从a[i…N]
获得的期望值。我们想要找到的是f(1)
。
请注意,+
中的第一个[i…N]
符号将显示在i
个元素之后,概率1/2
和i+1
元素的概率为{{1} }} 等等。只需找到按位或元素直到1/4
并添加剩余的期望值。
因此我们有了复发
+
这应该易于有效地实施而不会出错。
对于示例数组f(i) = sum_{j = i to N-1} (or(a[i…j]) + f(j+1))/(2^(j-i+1))
+ or(a[i…N])/(2^(N-i))
:
正如预期的那样,答案是19/4。
答案 1 :(得分:0)
首先,由于有2ⁿ⁻¹
个表达式(在数字之间的每个n-1
位置上有两个可能的运算符)并且它们都是同等可能的,因此期望值是所有表达式的总和除以2ⁿ⁻¹
。所以问题归结为计算表达式的总和。
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"
形式的表达式总和
S_(k-1) + x_k * N_(k-1)
"... + 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
形成的表达式的总和,然后0
是31
形成的表达式的总和。这意味着,问题可以减少到找到1位数字的表达式之和。从x_1, x_2, ..., x_n
到x_i
的每个位位置都可以单独处理,找到解决方案后我们只需添加它们即可。
让0
为一位数(每1
为S_k
或x_1, x_2, ..., x_k
)。
让N0_k
为N1_k
形成的表达式的总和。
令S_k
为最后一个加数等于0的此类表达式的数量。
令N0_k
为最后一个加数等于1的此类表达式的数量。
以下是允许查找N1_k
,x_k
和S_(k-1)
仅知道N0_(k-1)
,N1_(k-1)
,k = 1, x_1 = 0
和{的常规关系{1}}:
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)))
为数字的上限。
实施:
{{1}}