C++之线性DP 引言线性dp用来解决线性一维最大/最小问题可以降低时间复杂度先看题描述八戒押 x 两银子猫掌柜给定一个乱序数组 arr长度为 N有正数也有负数正数表示赢钱负数表示输钱。求 arr 的一个连续子数组使得子数组的和最大这样八戒才能尽可能的赢钱。这个和最大的子数组叫做最大子段和。输入描述第一行有两个数字分别是 x 和 N用空格隔开。第二行有 N 个数字用空格隔开表示数组元素。输出描述输出八戒最多赢多少钱若八戒想即时止损则输出一个负数表示八戒最少输多少钱。样例输入 112 8 1 -2 3 10 -4 7 2 -5样例输出 16提示1≤x,N≤100000最大子数组为[3 10 -4 7 2]和为18八戒押了12两银子所以最后赢6两分析这道题如果没学过线性dp第一眼看上去会很茫然。其实这是一道经典问题——最大子段和。那么问题来了总不能把所有子段枚举一遍吧聪明的你想到了这种方法dp[1] arr[1]; for (int i 1; i n; i) { if (dp[i - 1] 0) { dp[i] arr[i]; } else { dp[i] arr[i] dp[i - 1]; } max_s max(max_s, dp[i]); } cout max_s;恭喜你发明了最大子段和算法。再看一道题描述一个数的序列 bi​当 b1​b2​...bS​ 的时候我们称这个序列是上升的。对于给定的一个序列 (a1​,a2​,...,aN​)我们可以得到一些上升的子序列 (ai1​​, ai2​​, …, aiK​​)这里 1≤i1​i2​...iK​≤N。比如对于序列(1,7,3,5,9,4,8)有它的一些上升子序列如(1,7),(3,4,8)等等。这些子序列中和最大为 18为子序列(1,3,5,9)的和。你的任务就是对于给定的序列求出最大上升子序列和。注意最长的上升子序列的和不一定是最大的比如序列 (100,1,2,3) 的最大上升子序列和为 100而最长上升子序列为 (1,2,3)。输入描述输入的第一行是序列的长度 N(1≤N≤1000)。第二行给出序列中的 N 个整数这些整数的取值范围都在 0 到 10000(可能重复)。输出描述最大上升子序列和。样例输入 17 111111 7 3 5 9 4 11111样例输出 1111111提示1≤N≤1000分析这题和上一题差不多都求最大和这里就直接上代码了#include bits/stdc.h using namespace std; int n, dp[1009], a[1009], ans; int main() { cin n; for (int i 1; i n; i) { cin a[i]; dp[i] a[i]; } for (int i 2; i n; i) { for (int j 1; j i; j) { if (a[i] a[j]) { dp[i] max(dp[i], a[i] dp[j]); } } } for (int i 1; i n; i) { ans max(ans, dp[i]); } cout ans; return 0; }再来一道题描述一个数的序列 bi​当 b1​b2​...bS​ 的时候我们称这个序列是上升的。对于给定的一个序列 (a1​,a2​,...,aN​)我们可以得到一些上升的子序列(ai1​,ai2​,...,aiK​)这里1≤i1​,1≤i2​,...,1≤ik​≤N.比如对于序列 (1,7,3,5,9,4,8)有它的一些上升子序列如(1,7),(3,4,8)等等。这些子序列中最长的长度是4比如子序列(1,3,5,8)。你的任务就是对于给定的序列求出最长上升子序列的长度。输入描述输入的第一行是序列的长度 N(1≤N≤1000)。第二行给出序列中的 N 个整数这些整数的取值范围都在 0 到 10000。输出描述最长上升子序列的长度。样例输入 17 1 7 3 5 9 4 8样例输出 14分析这题和上一题的唯一区别就在于求长度or和稍微改一下代码就行了第八行初始化改为dp[i] 1;第13行改为dp[i] max(dp[i], dp[j] 1);小结线性dp往往是解决实际问题的基础学好线性dp竞赛中才能尽可能少出现TLE的问题