1049 最大子段和
N个整数组成的序列a[1],a[2],a[3],…,a[n],求该序列如a[i]+a[i+1]+…+a[j]的连续子段和的最大值。当所给的整数均为负数时和为0。
例如:-2,11,-4,13,-5,-2,和最大的子段为:11,-4,13。和为20。
收起
输入
第1行:整数序列的长度N(2 <= N <= 50000)
第2 - N + 1行:N个整数(-10^9 <= A[i] <= 10^9)
输出
输出最大子段和。
输入样例
6
-2
11
-4
13
-5
-2
输出样例
20
题意:
求某一子串的最大和
样例是 : 11 + -4 + 13 = 20
方法一:动态规划
在求解 dp[i] 的时候同时求出 最大值
CODE :
#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <algorithm>
#include <set>
#include <map>
#include <queue>
typedef long long LL;
using namespace std;
#define memset(a,n) memset(a,n,sizeof(a))
#define INF 0x3f3f3f3f
const int M = 5e4+10;
LL dp[M],a[M];
int main()
{
int n;
cin >> n;
for(int i=0; i<n; i++)
cin >> a[i];
LL maxx = -1;
for(int i=0; i<n; i++){
dp[i] = max(dp[i-1] + a[i],a[i]);
if(dp[i] > maxx) // 同时求出最大值
maxx = dp[i];
}
cout << maxx << endl;
}
方法二 、暴力求解(适合数据量较小的情况,这个题目会 T )
// 暴力求解
#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <algorithm>
#include <set>
#include <map>
#include <queue>
typedef long long LL;
using namespace std;
#define memset(a,n) memset(a,n,sizeof(a))
#define INF 0x3f3f3f3f
const int M = 5e4+10;
LL a[M];
int main()
{
ios::sync_with_stdio(false);
int n;
cin >> n;
for(int i=0; i<n; i++)
cin >> a[i];
LL ans = 0;
for(int i=0; i<n; i++){
for(int j=i; j<n; j++){
LL sum = 0;
for(int k=i; k<=j; k++)
sum += a[k];
ans = max(ans,sum);
}
}
cout << ans << endl;
}
// 暴力优化
// 求出当前位置的最大值,在继续求后边的和就好
#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <algorithm>
#include <set>
#include <map>
#include <queue>
typedef long long LL;
using namespace std;
#define memset(a,n) memset(a,n,sizeof(a))
#define INF 0x3f3f3f3f
const int M = 5e4+10;
LL dp[M],a[M];
int main()
{
int n;
cin >> n;
for(int i=0; i<n; i++)
cin >> a[i];
LL maxx = -1;
LL sum = 0;
for(int i=0; i<n; i++){
sum = 0;
for(int j=i; j<n; j++){
sum += a[j];
if(sum > maxx)
maxx = sum;
}
}
cout << maxx << endl;
}
方法三 分治法
如果将所给的序列a[1:n]分为长度相等的两段子序列a[1:n/2]和a[n/2+1:n],分别求出这两段子序列的最大子段和,则总序列的最大子段和有三种情况:
1)与前段相同
2)与后段相同
3)跨前后两段
#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <algorithm>
#include <set>
#include <map>
#include <queue>
typedef long long LL;
using namespace std;
#define memset(a,n) memset(a,n,sizeof(a))
#define INF 0x3f3f3f3f
const int M = 5e4+10;
LL dp[M],a[M];
LL maxSum(int l,int r)
{
if(l == r){
if(a[l] > 0)
return a[l];
else
return 0;
}
int mid = (l + r) / 2;
LL lsum = maxSum(l,mid);
LL rsum = maxSum(mid+1,r);
LL sum=0,sum1=0,maxx=0,maxx1=0;
// 由于求的是跨越两个子段,所以从中间点位置开始求和
// 切记不能从 [l,mid] 求解
for(int i=mid;i>=l;i--){
sum += a[i];
if(sum > maxx)
maxx = sum;
}
for(int i=mid+1; i<=r; i++){
sum1 += a[i];
if(sum1 > maxx1)
maxx1 = sum1;
}
LL ans = 0;
ans = maxx + maxx1;
if(ans < lsum)
ans = lsum;
if(ans < rsum)
ans = rsum;
return ans;
}
int main()
{
int n;
cin >> n;
for(int i=0; i<n; i++)
cin >> a[i];
LL ans = maxSum(0,n-1);
cout << ans << endl;
}