洛谷[P1115 最大子段和] {前缀和与差分} 奋斗的珂珂~

洛谷[P1115 最大子段和] {前缀和与差分}

题目描述

给出一个长度为 nn 的序列 aa,选出其中连续且非空的一段使得这段和最大。

输入格式

第一行是一个整数,表示序列的长度 nn。

第二行有 nn 个整数,第 ii 个整数表示序列的第 i个数字 ai。

输出格式

输出一行一个整数表示答案。

输入输出样例

输入
7
2 -4 3 -1 2 -4 3
输出
4

说明/提示

样例 解释
选取 [3,5] 子段 {3,−1,2},其和为4。

数据规模与约定

对于 40% 的数据,保证 n≤ 1 0 3 10^3 103
对于 100% 的数据,保证1≤n≤2× 1 0 5 10^5 105 ,− 1 0 4 10^4 104 ≤ai ≤ 1 0 4 10^4 104

解题思路

      虽然是经典的dp,但是既然在前缀和的题单里面发现了它,多学一种方法也是很好的,以备不时之需。

分两部分进行考虑
首先,考虑长度为一,也就是只有数组元素自身
之后,设置一个minn变量代表前i个数组元素的和的最小值。(注意最初设置为min(0,a[1]),如果是a[1]是正数,那么就取0,如果是负数,那么就取其本身。)
最后,只要求取前缀和减去minn的最大值就可以,与此同时需要不断更新minn,保证其是前n个数的最小值。这样既可以保证数据不断更新,还可以保证不出现超时的情况。

完整代码

#include
using namespace std;
const int maxn=2e5+10;
int a[maxn],b[maxn];
int minn=-1e9;//minn代表之前序列前缀和的最小值 

int main()
{
	int n;
	scanf("%d",&n);
	int ans=-1e9;
	for(int i=1;i<=n;i++)
	{
		scanf("%d",&a[i]);
		ans=max(ans,a[i]);//如果只取一个数的时候就是最大值 
		b[i]=b[i-1]+a[i];//求前缀和 
	}
	minn=min(0,a[1]);// 如果首位是正数那么就取0,如果首位是负数那么就取负数 
	for(int i=2;i<=n;i++)
   {
	   ans=max(ans,b[i]-minn);	//当前最大值与新的子序列和值作比较 
	   minn=min(minn,b[i]); //获取前缀和的最小值 
	}
	printf("%d",ans);
	return 0;
 } 

你可能感兴趣的:(前缀和与差分)