给出一个长度为 n n n 的序列 a a a,选出其中连续且非空的一段使得这段和最大。
第一行是一个整数,表示序列的长度 n n n。
第二行有 n n n 个整数,第 i i i 个整数表示序列的第 i i i 个数字 a i a_i ai。
输出一行一个整数表示答案。
7
2 -4 3 -1 2 -4 3
4
选取 [ 3 , 5 ] [3, 5] [3,5] 子段 { 3 , − 1 , 2 } \{3, -1, 2\} {3,−1,2},其和为 4 4 4。
当解决最大连续子序列和问题时,可以使用两种基本方法:暴力法和动态规划法。
暴力法是最直观的解决方法,它通过遍历所有可能的子序列,并计算它们的和,最后返回最大的和。具体步骤如下:
初始化一个变量 m a x x maxx maxx为负无穷大,用于记录最大和。
使用两个嵌套循环遍历所有可能的子序列起点和终点。
在内层循环中,计算当前子序列的和,并将其与 m a x x maxx maxx进行比较,更新 m a x x maxx maxx。
最后返回 m a x x maxx maxx作为结果。
例如,对于序列 [ − 2 , 1 , − 3 , 4 , − 1 , 2 , 1 , − 5 , 4 ] [-2, 1, -3, 4, -1, 2, 1, -5, 4] [−2,1,−3,4,−1,2,1,−5,4],暴力法将遍历所有可能的子序列,计算它们的和,并返回最大的和,即 6 6 6,对应子序列 [ 4 , − 1 , 2 , 1 ] [4, -1, 2, 1] [4,−1,2,1]。
暴力法的时间复杂度为 O ( n 2 ) O(n^2) O(n2),其中 n n n是序列的长度。
动态规划法是一种更高效的解决方法,它通过利用子问题的最优解来构建整个问题的最优解。具体步骤如下:
初始化两个变量 m a x x maxx maxx和 l l ll ll,分别用于记录全局最大和和当前子序列的和。
遍历整个序列,对于每个元素,将其与 l l ll ll相加,如果结果大于当前元素本身,则更新 l l ll ll为相加结果;否则,将 l l ll ll更新为当前元素。
在每次更新 l l ll ll时,将其与 m a x x maxx maxx进行比较,如果 l l ll ll大于 m a x x maxx maxx,则更新 m a x x maxx maxx为 l l ll ll。
最后返回 m a x x maxx maxx作为结果。
例如,对于序列 [ − 2 , 1 , − 3 , 4 , − 1 , 2 , 1 , − 5 , 4 ] [-2, 1, -3, 4, -1, 2, 1, -5, 4] [−2,1,−3,4,−1,2,1,−5,4],动态规划法将遍历整个序列,计算当前子序列的和,并更新 m a x x maxx maxx和 l l ll ll。最终,返回 m a x x maxx maxx的值为 6 6 6,对应子序列 [ 4 , − 1 , 2 , 1 ] [4, -1, 2, 1] [4,−1,2,1]。
动态规划法的时间复杂度为 O ( n ) O(n) O(n),其中 n n n是序列的长度。
总结: 暴力法是一种简单直观的解决方法,但在处理大规模序列时效率较低。动态规划法通过利用子问题的最优解,将问题分解为更小的子问题,从而提高了效率。在实际应用中,动态规划法是解决最大连续子序列和问题的常用方法。
#include
using namespace std;
long long n,a,ll,maxx;
int main() {
cin >>n >>a;
ll=a; maxx=a;
for (int i=2;i<=n;i++)
{
cin >>a;
if (ll+a<0)
ll=0;
else
{
ll+=a;
maxx=max(maxx,ll);
}
}
cout <<maxx;
return 0;
}