洛谷P1115 最大子段和 (线性DP)

经典的线性DP例题,用f[i]表示以第i个位置结尾的最大连续子段和。

状态转移方程:f[i]=max(f[i],f[i-1]+a[i]);

这里省去了a数组,直接用f数组读数据,如果f[i-1]<0,那么f[i]肯定不会加上它,f[i]=a[i],相当于是从此时的i位置重新计算最大连续子段和;如果f[i-1]>=0,那它对f[i]来说是有贡献的,要加上它。

代码很短:

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 const int N = 2e5 + 10, inf = 1e9;
 4 int n, f[N], ans = -inf;
 5 int main() {
 6     cin >> n; 
 7     for (int i = 1; i <= n; i ++) {
 8         cin >> f[i];
 9         f[i] = max(f[i], f[i - 1] + f[i]);
10         ans = max(ans, f[i]);
11     }
12     cout << ans;
13 }

 还可以对空间进行优化,我们可以发现,f[i]的值只可能与它前一个(即f[i-1])有关,用滚动数组就行了,这里就不再写上代码了。

update221010

另一种方法,一个连续子段可以转化为两个前缀相减,我们可以枚举后面的前缀,不断更新前面的前缀的最小值,更新答案即可。

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 const int N = 2e5 + 10, inf = 1e9 + 10;
 4 int n, sum[N];
 5 
 6 int main() {
 7     scanf("%d", &n);
 8     int ans = -inf, l = 0;
 9     for (int i = 1; i <= n; i ++) {
10         scanf("%d", &sum[i]);
11         sum[i] += sum[i - 1];
12         if (sum[i] - sum[l] > ans) ans = sum[i] - sum[l];
13         if (sum[i] < sum[l]) l = i;
14     }
15     printf("%d\n", ans);
16     return 0;
17 }
posted @ 2022-04-04 15:13  YHXo  阅读(42)  评论(0编辑  收藏  举报