最大字段和
问题描述
金金最喜欢做有挑战的事情了,比如说求区间最大子段和。
一开始,金金有n个数,第i个数字是ai。
金金又找来了一个新的数字P,并想将这n个数字中恰好一个数字替换成P。要求替换后的最大子段和尽可能大。
金金知道这个题目仍然很简单,所以如果你做不出来,金金就要和你谈一谈了。
注:最大子段和是指在n个数中选择一段区间[L,R](L<=R)使得这段区间对应的数字之和最大。
输入
第一行两个数n,p。
第二行一行n个数ai。
输出
一个数表示答案
输入实例
5 3
-1 1 -10 1 -1
输出示例
5
注意:
样例说明:将第三个数变成3后最大子段和为[2,4]。
数据范围:n<=1000,-1000<=ai,P<=1000。
问题分析
(1)题目含义:本题讲述到金金把一组数中的一个数替换掉之后,求最大的字段和。
(2)本题中根本含义还是求最大字段和,可用for循环将给出的数一一替换,每次循环后找到替换每个数后最大的字段和,再在这些最大的字段和中求最大。
(3)求最大字段和,可采用暴力枚举的形式(即求出这组数中的所有字段,分别求和,求最大)当然这种方法肯定会超时。
(4)我们可以采用dp(动态规划),具体思路如下:
定义一个后边界(在这段区间中,以这个数为最后的那个数(即边界))。
从前往后递推,如果前面的那组数是负值,考虑到加上这个值的最终值只会小,即
C [ i ] = max { C [ i − 1 ] + A [ i ] , A [ i ] } i = 2 , . . . , n C [ 1 ] = A [ 1 ] , \mathrm{C}\left[ \mathrm{i} \right] =\max \left\{ \mathrm{C}\left[ \mathrm{i}-1 \right] +\mathrm{A}\left[ \mathrm{i} \right] ,\mathrm{A}\left[ \mathrm{i} \right] \right\} \,\,\mathrm{i}=2,...,\mathrm{n}\\\mathrm{C}\left[ 1 \right] =\mathrm{A}\left[ 1 \right] , C[i]=max{C[i−1]+A[i],A[i]}i=2,...,nC[1]=A[1],
特别注意:存在全为负值的字段,因此我们需提前定义一个足够小的值做初始比较。
具体代码如下:
#include<bits/stdc++.h>
using namespace std;
int INF = 999999999;
int MaxSum(int a[], int n)
{
int tempSum = 0;
int maxSum = -INF;
for (int j = 1; j <= n; j++)
{
tempSum = (tempSum + a[j]) > a[j] ? (tempSum + a[j]) : a[j];
if (tempSum > maxSum)
maxSum = tempSum;
}
return maxSum;
}
int main()
{
int n, p;
int a[1001];
cin >> n>>p;
for (int i = 1; i <= n; i++)
{
cin >> a[i];
}
int maxsum[1001] = {0};
for (int i = 1; i <= n; i++)
{
int temp = a[i];
a[i] = p;
maxsum[i]=MaxSum(a,n);
a[i] = temp;
}
int max=maxsum[1];
for (int i = 2; i <= n; i++)
{
if (max < maxsum[i])
{
max = maxsum[i];
}
}
cout << max;
return 0;
}