理想汽车大模型笔试0925
选择
代码
题目:数组合并的最大贡献
给定一个整数数组 nums(长度为 n)。你可以重复执行“合并”操作,直到数组被合并成一个数。
合并规则
每次选择两个相邻的连续块 A 和 B 进行合并;
合并的“贡献”定义为这两个块元素之和的乘积:$$\text{contrib}(A,B)=\big(\sum A\big)\times\big(\sum B\big)$$
合并后得到一个新的块,其值为两块元素之和:new_block=∑A+∑B\text{new\_block}=\sum A+\sum Bnew_block=∑A+∑B
继续按照上述规则合并相邻块,直到只剩一个块。
你的任务是:在所有可能的合并顺序中,求总贡献的最大值。总贡献为每一步合并的贡献之和。
输入
第一行一个整数 n,表示数组长度。1 ≤ n ≤ 500
第二行包含 n 个整数,表示数组 nums 的元素。元素取值范围为[1,5000]
输出
一个整数,表示将整个数组合并为一个数时可以获得的最大总贡献。
说明
合并必须发生在相邻的连续块之间。
样例
输入
3
1 2 3
输出
11
解释
先合并 (1) 与 (2),贡献 1×2=2,形成块 3;再合并 (3) 与 (3),贡献 3×3=9;总贡献 2+9=11。
或先合并 (2) 与 (3),贡献 6,形成块 5;再合并 (1) 与 (5),贡献 5;总贡献 6+5=11。两种顺序的最大总贡献均为 11。
动态规划,比较难,要用到Knuth 优化。普通dp只能20%
没做出来
可能的正确答案:
# 示例输入
# n = int(input().strip())
# a = list(map(int, input().split()))
n = 3
a = [1, 2, 3]
# 前缀和与区间和
prefix_sum = [0] * (n + 1)
for i in range(n):
prefix_sum[i + 1] = prefix_sum[i] + a[i]
def seg_sum(l, r):
return prefix_sum[r + 1] - prefix_sum[l]
# dp[i][j]: 区间 [i, j] 的最大代价
# opt[i][j]: 取得最大代价的最优断点 k
dp = [[0] * n for _ in range(n)]
opt = [[0] * n for _ in range(n)]
for i in range(n):
dp[i][i] = 0
opt[i][i] = i
# 按长度递增;为使用 opt 的单调性,i 需从大到小遍历
for length in range(2, n + 1):
for i in range(n - length, -1, -1): # i: n-length -> 0
j = i + length - 1
# Knuth/四边形优化的搜索区间 [l, r]
l = opt[i][j - 1]
r = opt[i + 1][j] # 此时已在本轮前面算过
# 夹到合法范围 [i, j-1]
l = max(l, i)
r = min(r, j - 1)
best = float("-inf")
best_k = i
for k in range(l, r + 1):
left = dp[i][k]
right = dp[k + 1][j]
cost = seg_sum(i, k) * seg_sum(k + 1, j)
cur = left + right + cost
if cur > best:
best = cur
best_k = k
dp[i][j] = best
opt[i][j] = best_k
print(dp[0][n - 1]) # 例子输出 11
第二题没时间看了。
26秋招算法笔试 文章被收录于专栏
26秋招算法笔试