P1115 最大子段和 - 洛谷
题目描述
给出一个长度为 n
的序列 a
,选出其中连续且非空的一段使得这段和最大。
输入格式
第一行是一个整数,表示序列的长度 n
。
第二行有 n
个整数,第 i
个整数表示序列的第 i
个数字 aᵢ
。
输出格式
输出一行一个整数表示答案。
输入输出样例
输入 #1
7
2 4 -3 -1 -2 -4 3
输出 #1
4
说明/提示
样例 1 解释
选取 [3, 5]
子段 [3, -1, 2]
,其和为 4
。
数据规模与约定
- 对于 40% 的数据,保证
n ≤ 2 × 10³
。 - 对于 100% 的数据,保证
1 ≤ n ≤ 2 × 10⁶
,-10⁴ ≤ aᵢ ≤ 10⁴
。
思路:
递归,求出第i个为结尾的最长子数组的大小。
代码:
#include<bits/stdc++.h>
using namespace std;
const int N = 2e5+10;
int a[N],mem[N];
int n;
int dfs(int x)
{int sum = -1e9;if(x < 0)return 0; elsereturn max(a[x],dfs(x-1)+a[x]);
}
int main(void)
{cin >> n;for(int i = 1 ; i <= n ; i++){cin >> a[i];}int ans = -1e9;for(int i = 1 ; i <= n ; i++){ans = max(ans,dfs(i));}cout << ans;return 0;}
思路:
记忆化数组优化
代码:
#include<bits/stdc++.h>
using namespace std;
const int N = 2e5+10;
int a[N],mem[N];
int n;
int dfs(int x)
{if(mem[x] != -1)return mem[x];int sum = -1e9;if(x < 0)return -1e9; elsesum = max(a[x],dfs(x-1)+a[x]);mem[x] = sum;return sum;
}
int main(void)
{cin >> n;memset(mem,-1,sizeof(mem));for(int i = 1 ; i <= n ; i++){cin >> a[i];}int ans = -1e9;for(int i = 1 ; i <= n ; i++){ans = max(ans,dfs(i));}cout << ans;return 0;}
dp:
#include<bits/stdc++.h>
using namespace std;
const int N = 2e5+10;
int a[N],dp[N];
int n;
int main(void)
{cin >> n;for(int i = 1 ; i <= n ; i++){cin >> a[i];}for(int i = 1 ; i <= n ; i++){dp[i] = max(a[i],dp[i-1] + a[i]);}int ans = -1e9; for(int i = 1 ; i <= n ; i++){ans = max(ans,dp[i]);}cout << ans;return 0;}
贪心:
#include<bits/stdc++.h>
using namespace std;
const int N = 2e5+10;
int a[N],dp[N];
int n;
int main(void)
{cin >> n;for(int i = 1 ; i <= n ; i++){cin >> a[i];}int sum = 0,ans = -1e9;for(int i = 1 ; i <= n ; i++){if(sum < 0)sum = 0;sum += a[i];ans = max(ans,sum);}cout << ans;return 0;}
双指针:
#include <bits/stdc++.h>
using namespace std;
const int N = 2e5 + 10;
int a[N], n;
int main()
{cin >> n;for (int i = 1; i <= n; i++) {cin >> a[i];}int maxsum = a[1];int currentsum = 0;int left = 1;// 右指针扩展窗口for (int right = 1; right <= n; right++) {currentsum += a[right]; // 累加当前元素到当前和maxsum = max(maxsum, currentsum); // 更新最大和while (currentsum < 0 && left <= right) // 舍弃负值子段 {currentsum -= a[left];left++;}}cout << maxsum << endl;return 0;
}