最大连续字段和问题:一段连续字段和 最大子段和
我们可以通过前后缀分解来处理两段字段和
预处理g[i],表示1~i中最大的字段和
h[i] 表示i~n中最大的字段和
dp
状态表示:f[i]表示1~i中以i结尾的所有连续子序列的集合的最大值
状态计算:
- 只含i
- 区间长度至少是2, f[i] = max(w[i], f[i - 1] + w[i]) = w[i] + max(0, f[i - 1])
因为每个状态只依赖前一个状态,所以f[i]可以用一个字母s来表示
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 50010, INF = 1e9;
int n;
int w[N], g[N], h[N];
int f[N];
int main ()
{
int T;
cin >> T;
while(T --)
{
cin >> n;
for(int i = 1; i <= n; i ++) cin >> w[i];
f[0] = g[0] = -INF; //空的话无解,为负无穷,保证不会转移
for(int i = 1; i <= n; i ++)
{
f[i] = max(f[i - 1], 0) + w[i];
g[i] = max(g[i - 1], f[i]); //g[i]存的是前缀的最大值
}
h[n + 1] = f[n + 1] = -INF;
for(int i = n; i; i --)
{
f[i] = max(f[i + 1], 0) + w[i];
h[i] = max(h[i + 1], f[i]); //h[i]存的是后缀的最大值
}
int res = -INF;
for(int i = 1; i <= n; i ++)
res = max(res, g[i] + h[i + 1]);
cout << res << endl;
}
return 0;
}
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 50010, INF = 1e9;
int n;
int w[N], g[N], h[N];
int s;
int main ()
{
int T;
cin >> T;
while(T --)
{
cin >> n;
for(int i = 1; i <= n; i ++) cin >> w[i];
g[0] = -INF; //空的话无解,为负无穷,保证不会转移
for(int i = 1, s = -INF; i <= n; i ++) //这里一开始s要表示为-INF,表示一个数都没有,无解,保证不会转移
{
s = max(s, 0) + w[i];
g[i] = max(g[i - 1], s); //g[i]存的是前缀的最大值
}
h[n + 1] = -INF;
for(int i = n, s = -INF; i; i --)
{
s = max(s, 0) + w[i];
h[i] = max(h[i + 1], s); //h[i]存的是后缀的最大值
}
int res = -INF;
for(int i = 1; i <= n; i ++)
res = max(res, g[i] + h[i + 1]);
cout << res << endl;
}
return 0;
}