最大连续和(题解)
题目描述:
给出一个长度为n 的序列A1,A2,...,An,求最大连续和。换句话说,要求找到1<=i<=j<=n,使得Ai+Ai+1+...+Aj 尽量大。
输入格式:
第一行输入n(1<=n<=50000)。
接下来1 行输入序列的n 个元素,第i+1 行为Ai(|Ai|<=10000)。
输出格式:
输出一个数表示最大连续和。
样例输入输出:
4
2 -1 3 -2
4
数据范围:
30%的数据n<=100;
60%的数据n<=10000;
100%的数据n<=50000。
这道题有很多种方法,当然得的分也不尽相同:
#include <cstdio> #include <algorithm> #include <iostream> #include <cstdlib> #include <cmth> #include <cstring> #include <string> using namespace std; int a[50005],pre[50005]; typedef long long ll; ll ans; int main() { freopen("sum.in","r",stdin); freopen("sum.out","w",stdout); int n; scanf("%d",&n); for(int i = 1 ; i <= n ; i++) { scanf("%d",&a[i]); pre[i] = pre[i - 1] + a[i]; } for(int i = 1 ; i <= n ; i++) { for(int j = 1 ; j <= i ; j++) { ans = max(ans,ll(pre[i]-pre[j])); } } printf("%lld",ans); return 0; }
这里是用总体前缀和减去前位前缀和来计算和,但是这种方法是n^2的复杂度,只能得60分,虽然前缀和的方法很高大上,却还有一种方法更犇。
时间复杂度为O(n)的方法:
对于每一个数,将这个数与前几个数的和和下一个数进行比较,如果前者大的话,就取前面的那个,否则就从下一个数开始。这样保证每次加的数的和都是最大的(如果不是最大的,就从下一个数开始重新计算了),所以,特别神奇吧。
代码:
#include <iostream> #include <stdio.h> #include <string.h> #include <string> #include <stdlib.h> #include <vector> #include <algorithm> #include <math.h> using namespace std; const int MAXN=50050; int n,ans=-2147483647,dp[MAXN],a[MAXN]; int main() { scanf("%d",&n); for (int i=1;i<=n;i++) { scanf("%d",&a[i]); dp[i]=max(dp[i-1]+a[i],a[i]); ans=max(ans,dp[i]); } printf("%d\n",ans); return 0; }