题目描述
难度分:1900
输入n、k(1≤k≤n≤3×105)和长为n的数组a(−106≤a[i]≤106)。
把a分割成恰好k个非空连续子数组。
设S=第一个子数组的元素和乘以1+第二个子数组的元素和乘以2+…+第k个子数组的元素和乘以k。
输出S的最大值。
输入样例1
5 2
-1 -2 5 -4 8
输出样例1
15
输入样例2
7 6
-3 0 -1 -2 -2 -4 -1
输出样例2
-45
输入样例3
4 1
3 -1 6 0
输出样例3
8
算法
贪心
让数组的索引从0开始,如果将一个长度为4的数组a=[a0,a1,a2,a3]划分为[[a0],[a1,a2],[a3]],S=a0+(a1+a2)×2+a3×3,本质上就是(a0+a1+a2+a3)+(a1+a2+a3)+a3,即s[0]+s[1]+s[3],s[i]为后缀[i,n)的累加和。
这样就很容易看出思路了,s[0]是必选的,剩下k−1个后缀和选s[1…n−1]最大的k−1个即可。初始化答案ans=s[0],然后把s[1…n−1]追加到一个数组sums中,排个序将最大的k−1个累加到ans上就能得到最终答案。
复杂度分析
时间复杂度
预处理后缀和时间复杂度为O(n);对后缀和排序时间复杂度为O(nlog2n);把除了s[0]之外最大的k−1个后缀和加起来时间复杂度为O(k)。因此,时间复杂度为O(nlog2n)。
空间复杂度
后缀和数组s的空间是线性的,为O(n);将除了s[0]之外的后缀和追加到一个额外的sums数组中,也占用了O(n)的空间(这个空间可以省掉,但不影响空间复杂度,无关紧要);排序的空间复杂度参考快排,为O(log2n)。因此,整个算法的空间瓶颈就是线性的,额外空间复杂度为O(n)。
python 代码
n, k = map(int, input().split())
a = list(map(int, input().split()))
s = [0]*n
s[-1] = a[-1]
sums = [s[-1]]
for i in range(n - 2, -1, -1):
s[i] = s[i + 1] + a[i]
if i > 0:
sums.append(s[i])
sums.sort(reverse=True)
ans = s[0] + sum(sums[:k - 1])
print(ans)