2022 2.10
Given a set of n integers: A={a1, a2,..., an}, we define a function d(A) as below:
给定一组n个整数:A={a1,a2,…,an},我们定义函数d(A)如下:
t1 t2 d(A) = max{ ∑ai + ∑aj | 1 <= s1 <= t1 < s2 <= t2 <= n } i=s1 j=s2
d(A)为两段和的最大值,不相交。
Your task is to calculate d(A).
你的任务是计算d(A).
输入
The input consists of T(<=30) test cases. The number of test cases T is given in the first line of the input.
输入由T(<=30)个测试用例组成。测试用例的数量T在输入的第一行给出。
Each test case contains two lines. The first line is an integer n(2<=n<=50000). The second line contains n integers: a1, a2, ..., an. (|ai| <= 10000).There is an empty line after each case.
每个测试用例包含两行。第一行是一个整数n(2<=n<=50000)。第二行包含n个整数:a1,a2.....,(|ai |<=10000)。每个案例后面都有一个空行。
输出
Print exactly one line for each test case. The line should contain the integer d(A).
每个测试用例只打印一行。该行应包含整数d(A)的值。
样例输入
1 10 1 -1 2 2 3 -3 4 -4 5 -5
样例输出
13
提示
In the sample, we choose {2,2,3,-3,4} and {5}, then we can get the answer.
Huge input,scanf is recommended.
在样本中,我们选择{2,2,3,-3,4}和{5},然后我们可以得到答案。
投入巨大,建议使用scanf。
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
int a[50004],b[50004],c[50004]; //用b[]来储存从左往右的最大子段和
int main() //用c[]来储存从右往左的最大子段和
{
int t;
scanf("%d",&t); //输入数据较大,推荐使用scanf
while(t--)
{
memset(a,0,sizeof a); //先将三个数组清空
memset(b,0,sizeof b);
memset(c,0,sizeof c);
int n,ans=-1e9; //答案可能为负数,因此ans要为-1e9
scanf("%d",&n);
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);
b[0]=-1e9; //预处理,保证b[0]不会被取到
int sum=0; //当前子段和
for(int i=1;i<=n;i++)
{
b[i]=max(b[i-1],sum+a[i]); //状态转移方程
sum+=a[i];
if(sum<0) sum=0; //如果sum<0,为了保证sum子段和最大
} //要重新开始计算(即sum=0)
//同理,求从右往左的最大子段和
c[n+1]=-1e9;
sum=0;
for(int i=n;i>0;i--)
{
c[i]=max(c[i+1],sum+a[i]);
sum+=a[i];
if(sum<0) sum=0;
ans=max(ans,b[i]+c[i+1]); //遍历求最大值
}
printf("%d\n",ans);
}
return 0;
}