题意:给出若干个数,要求计算一个公式,公式是这些数排成一列后把他分成不相交的两部分(中间和两侧可以有若干个数不取),求出满足这样要求的一种分割方式,使得在这种分割方式下,被选入的数的和最大。
思路:在数列中任取一点i,求出这点左边的数的最大子序列和dp2[i],再求出这点右边的最大子序列和dp1[i],最后枚举分段点取所有dp2[i-1]+dp1[i]中的最大值就是答案。
而dp2和dp1的计算方法是:先求出以任意一点为终点的最长子序列left[i](还有以任意一点为起点的最长子序列right[i])然后dp2[i]就是i点左边的最大的left[i](dp1[i]就是i点右边最大的right[i])
下面是代码:
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <ctype.h>
#include <cstring>
#include <string>
#include <queue>
#include <cmath>
#define MAXN 50010
#define INF 2100000000
#define pu system("PAUSE")
#pragma comment(linker, "/STACK:16777216");
using namespace std;
int n;
int a[MAXN];
int dp1[MAXN];
int dp2[MAXN];
int main()
{
//freopen("C:/Users/Admin/Desktop/in.txt", "r", stdin);
int t;
cin >> t;
while(t--)
{
memset(dp2, 0, sizeof(dp2));
memset(dp1, 0, sizeof(dp1));
scanf("%d", &n);
for(int i = 0; i < n; i++)
{
scanf("%d", &a[i]);
}
int ans, ans1, ans2;
//先算右半截
dp1[n-1] = a[n-1];
for(int j = n-1; j >= 0; j--)
{
dp1[j] = max(dp1[j+1]+a[j], a[j]);
//ans1 = max(ans1, dp1[j]);
}
//再算左半截
dp2[0] = a[0];
for(int j = 1; j < n; j++)
{
dp2[j] = max(a[j], dp2[j-1]+a[j]);
//ans2 = max(ans2, dp2[j]);
}
//for(int i = 1; i < n-1; i++) dp2[i] = max(dp2[i], dp2[i-1]);
for(int i = n-2; i >= 0; i--) dp1[i] = max(dp1[i], dp1[i+1]);//前面i=n-1越界了WA到哭。。。
ans = dp2[0] + dp1[1];
for(int i = 1; i < n; i++)
{
ans = max(ans, dp2[i-1]+dp1[i]);
}
printf("%d\n", ans);
}
return 0;
}