题解:二次最大子段和求解。
此题可类比最大子段和,但如果把循环数组扩链处理后直接跑最大子段和,是不可行的,因为会导致子段和中元素数量大于循环数组长度。
换一个角度,该循环数组的最大子段和出现的位置有两种情况,一为原数组中间一段和最大,可直接跑最大子段和求解。二为首尾相接的部分最大,该种情况即是循环数组与非循环数组求最大子段和的区别所在,原因是数组中间部分出现了绝对值较大的负数,可以把数组取负,跑最大子段和后再与原数组和相加, 也可理解为求最小子段和。两种情况取最大值即可。
#include <bits/stdc++.h>
using namespace std;
const int N = 5e4 + 7;
typedef long long ll;
int n;
ll sum;
int a[N], dp[N];
ll solve_dp() // 求解数组最大子段和
{
ll res = INT_MIN, now = a[1];
for (int i = 2; i <= n; i ++) {
if (now > 0)
now += a[i];
else
now = a[i];
res = max(res, now);
}
return res;
}
int main()
{
ios::sync_with_stdio(0);
cin >> n;
for (int i = 1; i <= n; i ++)
cin >> a[i], sum += a[i];
ll ans = solve_dp();
for (int i = 1; i <= n; i ++) // 全部取负
a[i] = -a[i];
ans = max(ans, solve_dp() + sum);
cout << ans << endl;
return 0;
}