最大子段和DP前缀和C. Increase Subarray Sums

Posted 行码棋

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了最大子段和DP前缀和C. Increase Subarray Sums相关的知识,希望对你有一定的参考价值。

题目链接:
https://codeforces.com/contest/1644/problem/C

f ( k ) f(k) f(k)表示对一个数组中不同的k个元素做加x操作,最后的最大字段和。
f ( 0 ) , f ( 1 ) , . . . , f ( n ) f(0),f(1),...,f(n) f(0),f(1),...,f(n)


对数组a做前缀和
状态表示:
f [ i − j + 1 ] f[i-j+1] f[ij+1]:子段长度为i - j + 1的最大子段和
状态转移:
f [ i − j + 1 ] = m a x ( f [ i − j + 1 ] , s [ i ] − s [ j − 1 ] ) f[i-j+1] = max(f[i-j+1],s[i]-s[j -1]) f[ij+1]=max(f[ij+1],s[i]s[j1])

这个用动态规划求解最大子段和,复杂度 O ( N 2 ) O(N^2) O(N2)

f[0] = 0;
for(int i = 1; i <= n; i++)

	for(int j = 1; j <= i; j++)
		f[i - j + 1] = max(f[i - j + 1], s[i] - s[j - 1]);

因为还有增强的个数,所以最后统计需要加上增强的个数。

假设增强了j次,统计最大子段的长度为i,那么最多增强 m i n ( i , j ) min(i,j) min(i,j)次,在所有的情况中取最佳即可


#include<bits/stdc++.h>
using namespace std;

int main()

	ios::sync_with_stdio(false);
	cin.tie(nullptr);
	
	int t;
	cin >> t;
	while(t--)
	
		int n, x;
		cin >> n >> x;
		
		vector<int> a(n + 1), s(n + 1, 0);
		for(int i = 1; i <= n; i++)
		
			cin >> a[i];
			s[i] = s[i - 1] + a[i];
		
		
		vector<int> f(n + 1, -1e9);
		f[0] = 0;
		
		for(int i = 1; i <= n; i++)
		
			for(int j = 1; j <= i; j++)
				f[i - j + 1] = max(f[i - j + 1], s[i] - s[j - 1]);
		
		
		for(int i = 0; i <= n; i++)
		
			int res = 0;
			for(int j = 0; j <= n; j++)
				res = max(res, f[j] + min(i, j) * x);
			cout << res << " \\n"[i == n];
		
	
	return 0;


以上是关于最大子段和DP前缀和C. Increase Subarray Sums的主要内容,如果未能解决你的问题,请参考以下文章

算法初探系列14——线性DP进阶之最大子段和与最长上升子序列

51nod 1052 最大M子段和 & 1053 最大M子段和 V2

51nod 1050 循环数组最大子段和环形DP/最大子段和/正难则反

51Nod 1050 循环数组最大子段和 dp

环形数组 最大子段和 dp

最大子段和之环形问题