【备战秋招】每日一题:2023.07.20-OPPO算法-第三题-快速删除

文章介绍了如何利用期望动态规划解决一个问题:给定一个数组,每次随机选择一个元素并删除其后缀,求删除整个数组的期望次数。通过动态规划的方法,计算每个位置被选中的概率及其对期望次数的贡献,最终得出O(n^2)复杂度的解决方案。文章还提出了如果概率不变时,是否有O(n)复杂度算法的思考。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目描述

小欧拿到了一个数组, 她每次随机选择一个元素,然后将该元素以及其后缀全部删除。
已知第 i i i 个元素被选到的概率为 a i / s u m aᵢ/sum ai/sum ,其中 s u m sum sum 为当前数组所有元素之和。
小欧想知道, 将数组全部删完的期望次数是多少?

输入描述

第一行输入一个正整数 n n n ,代表数组的大小。( 1 ≤ n ≤ 100 1≤n≤100 1n100)
第二行输入 n n n 个正整数 a i aᵢ ai,代表数组的元素。( 1 ≤ a i ≤ 1 0 9 1≤aᵢ≤10⁹ 1ai109)

输出描述

一个浮点数,代表最终的期望次数。如果你的答案和正确答案的相对误差不超过10⁻⁵,则认为答案正确。

示例1

样例输入

2
13

样例输出

1.75

说明
25%的概率操作1次, 75%的概率操作2次,总期望次数为 1 ∗ 0.25 + 2 ∗ 0.75 = 1.75 1^{ \ast }0.25+2^{ \ast }0.75=1.75 10.25+20.75=1.75

思路:期望动态规划

考虑第一步:我们可以选择 n n n个位置。选完之后删掉后缀,那么显然留下的一定是原数组的一个前缀状态

那么考虑这个过程一定是让这个数组慢慢缩短,并且每次缩短,问题结构不发生变化。始终是一个连续的数组。我们可以考虑使用动态规划:

状态

d p i 代表考虑数组 A 的 [ 1 , i ] 的前缀的期望次数 dp_i 代表考虑数组A的[1,i] 的前缀的期望次数 dpi代表考虑数组A[1,i]的前缀的期望次数

转移

最开始,假设第一步选择了某个位置 j j j , 那么问题就从 A [ 1 , n ] A[1,n] A[1,n] 转化为 子问题 A [ 1 , j − 1 ] A[1,j-1] A[1,j1] 。 子问题的期望次数为 d p j − 1 dp_{j-1} dpj1 , 而选到第 j j j个位置的概率根据题目定义是: A [ j ] s u m ( A [ 1 , n ] ) \frac{A[j]}{sum(A[1,n])} sum(A[1,n])A[j]

所以选择 j j j贡献 d p j − 1 ∗ A [ j ] s u m ( A [ 1 , n ] ) dp_{j-1} * \frac{A[j]}{sum(A[1,n])} dpj1sum(A[1,n])A[j] 。枚举所有 j j j求和即为最终答案。

上述分析对于任意一个前缀 A [ 1 , i ] A[1,i] A[1,i] 都满足。所以转移方程为:
d p i = ∑ j = 1 i d p j − 1 ∗ A [ j ] s u m ( A [ 1 , i ] ) dp_i = \sum_{j=1}^{i} dp_{j-1} * \frac{A[j]}{sum(A[1,i])} dpi=j=1idpj1sum(A[1,i])A[j]
复杂度为 O ( n 2 ) O(n^2) O(n2) , 具体实现细节见代码!

思考问题

如果每次的概率不是变化的。即转移中的 A [ j ] s u m ( A [ 1 , i ] ) → A [ j ] s u m ( A [ 1 , n ] ) \frac{A[j]}{sum(A[1,i])} \rightarrow \frac{A[j]}{sum(A[1,n])} sum(A[1,i])A[j]sum(A[1,n])A[j] 。 你是否能够设计出一个 O ( n ) O(n) O(n)的算法?

代码

python

# Initialize DP table with length + 5 zeros
length = int(input())
dp = [0] * (length + 5)

# Base case: probability of choosing the first element is 1
dp[1] = 1

# Read in the array
array = list(map(int, input().split()))

# Fill in the DP table
for i in range(2, length + 1):
    # Calculate the total sum of the first i elements
    total_sum = sum(array[:i])
    for j in range(i):
        # Calculate the probability of choosing the jth element
        probability = array[j] / total_sum 
        # Update the DP table using the recurrence relation
        dp[i] += probability * (dp[j] + 1)

# Print the result
print(dp[length])
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

塔子哥学算法

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值