洛谷P1115 最大子段和 题解
题目描述
最大子段和是一道经典的动态规划问题。题目要求:给定一个包含n个整数的序列,找出其中和最大的连续子序列,并输出该最大和。若所有数均为负数,则取最大的那个数。
输入格式:
- 第一行一个整数n(1 ≤ n ≤ 2×10⁵)
- 第二行n个整数a₁,a₂,...,aₙ(-10⁴ ≤ aᵢ ≤ 10⁴)
输出格式:
- 输出一个整数,表示最大子段和
样例输入:
5
-2 11 -4 13 -5 -2
样例输出:
20
(对应子序列[11,-4,13])
解题思路
1. 动态规划(Kadane算法)
核心思想:维护两个关键变量
current_sum
:以当前元素结尾的最大子段和max_sum
:全局最大子段和
状态转移方程 :
c u r r e n t _ s u m = { a i if c u r r e n t _ s u m < 0 c u r r e n t _ s u m + a i otherwise current\_sum = \begin{cases} a_i & \text{if } current\_sum < 0 \\ current\_sum + a_i & \text{otherwise} \end{cases} current_sum={aicurrent_sum+aiif current_sum<0otherwise
m a x _ s u m = max ( m a x _ s u m , c u r r e n t _ s u m ) max\_sum = \max(max\_sum, current\_sum) max_sum=max(max_sum,current_sum)
2. 算法流程
- 初始化
current_sum = 0
,max_sum = -∞
- 遍历数组中的每个元素:
- 如果
current_sum < 0
,说明之前累计的和为负数,应舍弃,从当前元素重新开始 - 否则,将当前元素加入累计和
- 每次更新全局最大值
max_sum
- 如果
- 最终
max_sum
即为答案
代码解析
cpp
#include<bits/stdc++.h>
using namespace std;
int main() {
long long sum = 0; // 当前子段和
int x; // 临时存储输入值
int n;
cin >> n;
// 初始化最大值为最小可能的long long值
long long maxx = 0xffffffffffff;
maxx *= -1; // 等价于 LLONG_MIN
for (int i = 1; i <= n; ++i) {
cin >> x;
if (sum > 0) { // 累计和为正,继续扩展子段
sum += x;
maxx = max(maxx, sum);
} else { // 累计和为负,重新开始
sum = x;
maxx = max(maxx, sum);
}
}
cout << maxx;
return 0;
}
关键点说明
-
初始值设置:
maxx
初始化为0xffffffffffff * -1
,等价于-2^48
,确保能正确处理全负数情况- 更规范的写法是使用
#include <climits>
中的LLONG_MIN
-
决策逻辑:
- 当
sum > 0
时,继续累加当前元素可能获得更大和 - 当
sum ≤ 0
时,舍弃之前所有元素,从当前元素重新开始
- 当
-
时间复杂度:O(n)
- 仅需一次线性扫描即可完成计算
复杂度分析
指标 | 复杂度 | 说明 |
---|---|---|
时间复杂度 | O(n) | 单次遍历数组 |
空间复杂度 | O(1) | 仅使用常数级额外空间 |
边界情况测试
测试用例 | 预期输出 | 实际输出 | 说明 |
---|---|---|---|
1 -5 |
-5 | -5 | 单个负数元素 |
3 -1 -2 -3 |
-1 | -1 | 全负数序列 |
4 1 2 -3 4 |
6 | 6 | 包含负数的中间最优子段 |
5 -2 11 -4 13 -5 -2 |
20 | 20 | 经典样例 |
优化方向
-
输入优化:
- 使用
scanf/printf
替代cin/cout
可提升IO速度 - 添加
ios::sync_with_stdio(false)
加速C++流
- 使用
-
代码简化:
cpp// 简化版代码(功能完全等价) #include<bits/stdc++.h> using namespace std; int main() { int n, x; cin >> n; long long sum = 0, maxx = LLONG_MIN; while(n--) { cin >> x; sum = max((long long)x, sum + x); maxx = max(maxx, sum); } cout << maxx; return 0; }
总结
本题是动态规划的经典入门题,Kadane算法通过O(n)时间复杂度和O(1)空间复杂度完美解决问题。理解"舍弃负贡献"的核心思想是关键,这种贪心策略在许多序列问题中都有广泛应用。实际编码时需特别注意全负数等边界情况的处理。