题解:洛谷 P3009 Profits
【题目来源】
洛谷:P3009 [USACO11JAN] Profits S - 洛谷
【题目描述】
奶牛们开始了新的生意,它们的主人约翰想知道它们到底能做得多好。这笔生意已经做了 \(N(1\le N\le 10^5)\) 天,每天奶牛们都会记录下这一天的利润 \(P_i(\vert Pi\vert ≤1,000)\)。
约翰想要找到奶牛们在连续的时间期间所获得的最大的总利润。(注:连续时间的周期长度范围从第一天到第 \(N\) 天)。
请你写一个计算最大利润的程序来帮助他。
【输入】
第一行,一个单独的整数 \(N\)。
接下来 \(N\) 行,第 \(i+1\) 行包括一个单独的整数 \(P_i\)。
【输出】
一行,一个整数,表示任意连续时间段利润最大和的数值。
【输入样例】
7
-3
4
9
-2
-5
8
-3
【输出样例】
14
【核心思想】
-
问题分析:给定 \(N\) 天的利润序列 \(P_i\)(可为负数),求连续子数组的最大和。这是一个经典的最大子段和/线性DP问题,关键在于用动态规划维护以第 \(i\) 天结尾的连续子数组的最大和。
-
算法选择:
- 线性DP(Kadane算法):\(a[i]\) 表示以第 \(i\) 天结尾的连续子数组的最大和,转移方程为 \(a[i] = \max(a[i-1] + P_i,\ P_i)\),即要么延续前面的子数组,要么从第 \(i\) 天重新开始
-
关键步骤:
- 读取输入:\(N\) 和 \(N\) 天的利润 \(P_i\)
- 初始化:\(maxn = -\infty\)
- 线性DP(\(i\) 从 \(1\) 到 \(N\)):
- \(a[i] = \max(a[i-1] + a[i],\ a[i])\):以第 \(i\) 天结尾的最大子段和
- \(maxn = \max(maxn,\ a[i])\):更新全局最大值
- 输出 \(maxn\)
-
时间/空间复杂度:
- 时间复杂度:\(O(N)\)
- 空间复杂度:\(O(1)\),可滚动优化为仅维护前一个状态
-
Kadane算法的核心思想:
- 局部最优子结构:以第 \(i\) 天结尾的最大子段和,要么包含第 \(i-1\) 天的最优子段(延续),要么只包含第 \(i\) 天(重新开始)
- 负数处理:当 \(a[i-1] < 0\) 时,\(a[i-1] + P_i < P_i\),自动选择从 \(i\) 重新开始,避免负数拖累
- 全局最大值追踪:由于最大子段和可能出现在任意位置,需要维护全局最大值
- 适用于"连续子数组最大和"类经典问题,核心是 \(O(N)\) 的线性递推
【解题思路】

【算法标签】
普及- #线性DP-一维
【代码详解】
#include <bits/stdc++.h>
using namespace std;
int n, a[100005], maxn=-1e9;
int main()
{
cin >> n; // 输入n
for (int i=1; i<=n; i++) { // 输入n个数
cin >> a[i];
}
for (int i=1; i<=n; i++) { // 使用连续子序列最大和的模板
a[i] = max(a[i]+a[i-1], a[i]);
maxn = max(maxn, a[i]); // 每次计算完需要判断最大值
}
cout << maxn << endl; // 输出最大值
return 0;
}
【运行结果】
7
-3
4
9
-2
-5
8
-3
14
浙公网安备 33010602011771号