子段和问题
我们知道线性dp中一道典中典的题目就是求最大子段和;
状态方程为:dp[i]=max(dp[i]+a[i],a[i]);
当然这只是最基础的,还有很多扩展;
-
子段长度不大于m的最大子段和
这个时候dp已经不好用了,可以考虑前缀和sum[i],维护min(sum[k])(i-m<=k<i),然后只要sum[i]-sum[k]就可以了,具体怎么维护可以单调队列(模板题); -
子段长度不小于m的最大子段和
(1)第一种方法,先用dp计算一次没有长度限制的最大子段和,然后
f[i]=dp[i-1]+sum[i+m]-sum[i-1],最后对每一个f[i]求一个max;这个就是相当于在每个dp[i-1]后面加一个长度为m的段;
(2)直接维护min(sum[k])(1<=k<=i−m),这个维护就不要单调队列,直接一遍循环维护就行; -
环状最大子段和
(1)破环为链(长度扩大两倍),然后维护一个长度不大于m(m为环的长度)的最大子段和
(2)这种方法在后面求两段和也要用到,非常重要;
就是考虑这个子段是否经过连接点(就是同时经过a[1]和a[n]),如果经过,可以求1-n的最小子段和,然后总和减去这个最小子段和;如果不经过,就直接求1-n的最大子段和就可以; -
环状最大两段子段和
就是第3种的一个扩展,求两段,只要正向反向维护一个最大子段和就可以;
具体讲一下,为什么经过连接点要那样算?
可以发现环状的最大子段和要不就是-----++++ ----++++ ----(把环拆成链,长度没有扩大两倍,加号代表该位置取,减号代表不取),要不就是++++ ------++++ ----+++,也就是说要不就经过连接点,要不就不经过;
如果不经过,那么和普通的线性没区别;如果经过,那么就有三段子段和,不好求,正难则反,所以只要求最小子段和就可以了;
题目:洛谷·P1121 环状最大两段子段和