P1115 最大子段和

没错,我变菜了。。。

这道题可以用贪心的递推\(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)));
}
posted @ 2018-08-31 11:21  Garen-Wang  阅读(170)  评论(0编辑  收藏  举报