题解 P1115 【最大子段和】
几年就这么过去了,曾经并不注意格式规范导致现在题解不太美观。这里重新修正一下。这篇题解赞数不低,这里也只是修改 markdown 格式和分段排版,希望管理能给过。
又来水题解了。
题目传送门:Link。
大家不要把这题想得很复杂,能做出一个题首先要有做题的信念。这题的实际难度没有大家想得那么高。
直接枚举
首先,我们现在纸上手算一下样例是怎么来的:
2 -4 3 -1 2 -4 3
ans:4
可以发现选 3 -1 2 是一种合法的方案。那么是怎么推出来的呢?
首先看到第一个数,是
随后是
下一个数是
接下来是
然后是
最后一个数
最后我们来看一看刚推导的结果,发现
所以说了这么多,最终的结果是什么呢?
- 第一个数为一个有效序列
- 如果一个数加上上一个有效序列得到的结果比这个数大,那么该数也属于这个有效序列。
- 如果一个数加上上一个有效序列得到的结果比这个数小,那么这个数单独成为一个新的有效序列
- 在执行上述处理的过程中实时更新当前有效序列的所有元素之和并取最大值。
然后就可能有人问了:考虑上面样例推导中,出现了一个可加可不加的
结论是:对于可加可不加的数,不如加上。因为加上对答案没有坏处,而如果这个数后面还有一部分能让答案变多,因为本题求的子段是连续子段,不加上的话这两边就连不起来了。所以无脑加就行了。
最后取最大值即可。
#include<bits/stdc++.h>
using namespace std;
int n,a[200020],b[200020],i,ans=-2147483647;
// b[i] 表示截止到 i 时,第 i 个数所在的有效序列的元素和。
int main(){
cin>>n;
for(i=1;i<=n;i++){
cin>>a[i];
if(i==1) b[i]=a[i];
else b[i]=max(a[i],b[i-1]+a[i]);
ans=max(ans,b[i]);
}
cout<<ans;
return 0;
}
然而对比这份代码的时空消耗,我们还可以做得更好。
我们来看一眼代码:
- 输入
a_i 。 - 用
b_{i-1} 和当前输入的a_i 给b_i 赋值。 - 用
b_i 给ans 更新答案。
首先发现全程中
其次考虑
最终我们就得出了空间消耗大优化后的代码:
#include<bits/stdc++.h>
using namespace std;
int n,a,b,i,ans=-2147483647;
int main(){
cin>>n;
for(i=1;i<=n;i++){
cin>>a;
if(i==1) b=a;
else b=max(a,a+b);
ans=max(ans,b);
}
cout<<ans;
return 0;
}
空间优化的效果还是很明显的,从 2.13MB 变成了 688KB。