题目:你被给予了一个n个整数的数组a。数组的下标从0开始。你可以逆置一个数组的子数组(连续的)最多一次,你的任务是使得这个数组的偶数位置的数字的和最大。
分析:奇数长度的子数组翻转并不会改变偶数位置的数字,因此,我们只需要考虑长度为偶数的子区间。偶数长度的子数组我们有两种情况,一种是偶数位置开始,奇数位置结束,另一种是奇数位置开始,偶数位置结束。我们先考虑第一种情况,我们要求出一个子区间翻转的收益,我们存储每个位置的(a[i + 1] - a[i]),i从0开始,每次+2,我们要求出一个连续子段和的最大值,这可以联想到DP-最大连续子段和,对于一个位置的数,如果前缀和 <= 0,那么对于当前的数来说,加上这个前缀不会使得收益变大,因此我们重新令前缀和统计为0。这样两种情况求出后,我们加上这个收益,就是答案。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <vector>
#include <algorithm>
using namespace std;
using LL = long long;
const int N = 200005;
int a[N];
int main()
{
int t;
scanf("%d", &t);
while (t--)
{
int n;
scanf("%d", &n);
LL sum = 0;
for (int i = 0; i < n; ++i)
{
scanf("%d", &a[i]);
if ((i & 1) == 0) sum += a[i];
}
LL mx = 0;
LL diff1 = 0;
//偶开头
for (int i = 0; i + 1 < n; i += 2)
{
diff1 += a[i + 1] - a[i];
diff1 = max(0LL, diff1);
mx = max(mx, diff1);
}
LL diff2 = 0;
for (int i = 1; i + 1 < n; i += 2)
{
diff2 += a[i] - a[i + 1];
diff2 = max(0LL, diff2);
mx = max(mx, diff2);
}
printf("%lld
", sum + mx);
}
return 0;
}