没错,我变菜了。。。
这道题可以用贪心的递推\(O(n)\)地搞过去。
但是因为线段树和平衡树也要支持最大子序列,所以回来了解一波\(O(nlogn)\)的算法。
算法思想也非常常见:分治法。
对于一个区间\([l,r]\),我们从中间给他分开,变成\([l,mid]\)和\([mid+1,r]\)这两个区间。
而最大子序列可能出现的地方就有三个。一个在左区间,一个横跨左右区间,一个在右区间。
对于全部在一个区间的,我们递归搞一搞。
对于横跨左右区间的,我们可以暴力\(O(n)\)地枚举左区间内以\(mid\)结束的最大子序列和右区间内以\(mid+1\)开始的最大子序列,两个相加就完事了。
代码:
int solve(int l, int r)
{
if(l == r) return a[l];
int mid = (l + r) >> 1;
int rec1 = -INF, rec2 = -INF;
int sum = 0;
for(int i = mid; i >= l; i--)
{
sum += a[i];
rec1 = std::max(rec1, sum);
}
sum = 0;
for(int i = mid + 1; i <= r; i++)
{
sum += a[i];
rec2 = std::max(rec2, sum);
}
return std::max(rec1 + rec2, std::max(solve(l, mid), solve(mid + 1, r)));
}