题目:你被给予了一个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\n", sum + mx);
	}


	return 0;
}