题目链接:http://acm.csu.edu.cn/csuoj/problemset/problem?pid=1529
题解:
一个加强版的最大连续和子序列,序列可以从末尾元素转到首元素。
分两种情况:
1.最大连续和不需要尾接首,直接dp出以a[i]为结尾的最大连续和ma[i]。
2.最大连续和需要尾接首,先dp出以a[i]为结尾的最小连续和mi[i],然后再用总和sum减去mi[i],得到的即为减去中间部分的尾接首序列和(逆向思维)。最后再用max()取最大值。
代码如下:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <string>
#include <vector>
#include <map>
#include <set>
#include <queue>
#include <sstream>
#include <algorithm>
using namespace std;
#define pb push_back
#define mp make_pair
#define ms(a, b) memset((a), (b), sizeof(a))
//#define LOCAL
#define eps 0.0000001
#define LNF (1<<60)
typedef long long LL;
const int inf = 0x3f3f3f3f;
const int maxn = 2000000+10;
const int mod = 1e9+7;
LL a[maxn];
LL ma[maxn], mi[maxn];
void solve()
{
int n;
scanf("%d",&n);
LL sum = 0;
for(int i = 1; i<=n; i++)
scanf("%lld",&a[i]), sum += a[i];
LL now = 0;
for(int i = 1; i<=n; i++)//最大连续和
{
if(now>=0)
ma[i] = a[i]+now, now += a[i];
else
ma[i] = a[i], now = a[i];
}
now = 0;
for(int i = 1; i<=n; i++)//最小连续和
{
if(now<= 0)
mi[i] = a[i] + now, now += a[i];
else
mi[i] = a[i], now = a[i];
}
LL ans = ma[1];
for(int i = 1; i<=n; i++)//寻找最大值
{
ans = max(ans, ma[i]);
ans = max(ans, sum-mi[i]);
}
printf("%lld\n",ans);
}
int main()
{
#ifdef LOCAL
freopen("input.txt", "r", stdin);
// freopen("output.txt", "w", stdout);
#endif // LOCAL
int t;
scanf("%d", &t);
while(t--){
solve();
}
return 0;
}