预期的表达价值

时间:2017-01-19 18:51:50

标签: algorithm math

如何以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

2 个答案:

答案 0 :(得分:0)

重要的观察是每个+将其左右部分分成可以独立处理的部分。

让数组为a[1…N]。将f(i)定义为从a[i…N]获得的期望值。我们想要找到的是f(1)

请注意,+中的第一个[i…N]符号将显示在i个元素之后,概率1/2i+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))

  • f(3)=或(a [3 ... 3])= 3
  • f(2)=(或(a [2 ... 2])+ f(3))/ 2 +或(a [2 ... 3])/ 2 = 5/2 + 3/2 = 4
  • f(1)=(或(a [1 ... 1])+ f(2))/ 2 +(或(a [1 ... 2])+ f(3))/ 4 +或(a [ 1 ... 3])/ 4 = 5/2 + 6/4 + 3/4 = 19/4

正如预期的那样,答案是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

我们的想法是将所有可能的表达式除以最后"+"的位置。

  1. "... + x_k"形式的表达式总和
    • S_(k-1) + x_k * N_(k-1)
  2. "... + x_(k-1) | x_k"形式的表达式总和
    • S_(k-2) + (x_(k-1) | x_k) * N_(k-2)
  3. "... + x_(k-2) | x_(k-1) | x_k"形式的表达式总和
    • S_(k-2) + (x_(k-2) | x_(k-1) | x_k) * N_(k-3)
  4. ...依此类推,直到单个表达式x_1 | x_2 | ... | x_k
  5. 这是算法的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))

    该问题有两个属性可用于创建更快的算法。

    1. 如果S_n是数字x_1, x_2, ..., x_n形成的表达式的总和,则2*S_n是数字2*x_1, 2*x_2, ..., 2*x_n形成的表达式的总和。
    2. 如果x_1, x_2, ..., x_ny_1, y_2, ..., y_nx_k & y_m == 0k m SX_n而言x_1, x_2, ..., x_n,那么SY_n就是所形成的表达式的总和按y_1, y_2, ..., y_nSX_n + SY_nx_1+y_1, x_2+y_2, ..., x_n+y_n形成的表达式的总和,然后031形成的表达式的总和。
    3. 这意味着,问题可以减少到找到1位数字的表达式之和。从x_1, x_2, ..., x_nx_i的每个位位置都可以单独处理,找到解决方案后我们只需添加它们即可。

      0为一位数(每1S_kx_1, x_2, ..., x_k)。

      N0_kN1_k形成的表达式的总和。

      S_k为最后一个加数等于0的此类表达式的数量。

      N0_k为最后一个加数等于1的此类表达式的数量。

      以下是允许查找N1_kx_kS_(k-1)仅知道N0_(k-1)N1_(k-1)k = 1, x_1 = 0和{的常规关系{1}}:

      1. S_1 = 0
        • N0_1 = 1
        • N1_1 = 0
        • k = 1, x_1 = 1
      2. S_1 = 1
        • N0_1 = 0
        • N1_1 = 1
        • k > 1, x_k = 0
      3. 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
      4. 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
      5. 由于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}}