每日c/c++题 备战蓝桥杯(洛谷P1115 最大子段和)

洛谷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. 算法流程

  1. 初始化current_sum = 0max_sum = -∞
  2. 遍历数组中的每个元素:
    • 如果current_sum < 0,说明之前累计的和为负数,应舍弃,从当前元素重新开始
    • 否则,将当前元素加入累计和
    • 每次更新全局最大值max_sum
  3. 最终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;
}

关键点说明

  1. 初始值设置

    • maxx初始化为0xffffffffffff * -1,等价于-2^48,确保能正确处理全负数情况
    • 更规范的写法是使用#include <climits>中的LLONG_MIN
  2. 决策逻辑

    • sum > 0时,继续累加当前元素可能获得更大和
    • sum ≤ 0时,舍弃之前所有元素,从当前元素重新开始
  3. 时间复杂度: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 经典样例

优化方向

  1. 输入优化

    • 使用scanf/printf替代cin/cout可提升IO速度
    • 添加ios::sync_with_stdio(false)加速C++流
  2. 代码简化

    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)空间复杂度完美解决问题。理解"舍弃负贡献"的核心思想是关键,这种贪心策略在许多序列问题中都有广泛应用。实际编码时需特别注意全负数等边界情况的处理。

相关推荐
津津有味道1 小时前
Qt C++串口SerialPort通讯发送指令读写NFC M1卡
linux·c++·qt·串口通信·serial·m1·nfc
让我们一起加油好吗1 小时前
【C++】list 简介与模拟实现(详解)
开发语言·c++·visualstudio·stl·list
傅里叶的耶1 小时前
C++系列(二):告别低效循环!选择、循环、跳转原理与优化实战全解析
c++·visual studio
猫猫的小茶馆2 小时前
【STM32】预分频因子(Prescaler)和重装载值(Reload Value)
c语言·stm32·单片机·嵌入式硬件·mcu·51单片机
JeffersonZU2 小时前
Linux/Unix文件IO(文件描述符、原子操作、文件数据结构、open、read、write、fcntl、dup)
linux·c语言·unix·gnu
Vitta_U2 小时前
MFC的List Control自适应主界面大小
c++·list·mfc
Dovis(誓平步青云)3 小时前
基于探索C++特殊容器类型:容器适配器+底层实现原理
开发语言·c++·queue·适配器·stack
pipip.4 小时前
UDP————套接字socket
linux·网络·c++·网络协议·udp
智者知已应修善业5 小时前
【51单片机用数码管显示流水灯的种类是按钮控制数码管加一和流水灯】2022-6-14
c语言·经验分享·笔记·单片机·嵌入式硬件·51单片机
孞㐑¥9 小时前
Linux之Socket 编程 UDP
linux·服务器·c++·经验分享·笔记·网络协议·udp