CodeForces 1373 - D. Maximum Sum on Even Positions - 分类求最大连续子段和 ,思维

题目传送门:D. Maximum Sum on Even Positions

题目大意

给定一个数组,至多翻转一个子数组,使得偶数下标元素之和ans最大,输出ans(注意题目的数组下标从0开始)

思路

很显然我们要翻转偶数长度的子数组(因为奇数长度数组两端下标奇偶性相同,数组奇偶性呈中心对称,翻转之后奇数下标仍为奇数下标,偶数下标仍为偶数下标,那么翻转是无意义的),翻转之后奇偶下标互换

我们希望偶数下标元素之和最大,那么我们就要使翻转的数组中sum_奇 - sum_偶最大(因为翻转的数组下标奇偶性互换),想一想这不就是最大连续子段和吗?

但是需要注意的是我们要分别针对奇数下标开始的偶数下标开始的子数组求最大子段和(因为长度为偶数)

那么最后答案就是ans = 原数组sum_偶 + 子数组max(sum_奇 - sum_偶)

代码

#include 
using namespace std;
#define pb push_back
#define mp make_pair
#define fi first
#define se second
typedef long long ll;
typedef unsigned long long ull;
typedef pair PII;
typedef pair pll;
const int mod = 1e9 + 7;
const int N = 2e5 + 10;
const int INF = 0x3f3f3f3f;
ll qpow(ll base, ll n){ll ans = 1; while (n){if (n & 1) ans = ans * base % mod; base = base * base % mod; n >>= 1;} return ans;}
ll gcd(ll a, ll b){return b ? gcd(b, a % b) : a;}
ll a[N];
int main()
{
	int t;
	cin >> t;
	while (t --){
		int n;
		cin >> n;
		ll ans = 0, sum[2] = {0, 0}, maxsum = 0;
		for (int i = 1; i <= n; ++ i){
			scanf("%lld", &a[i]);
			if (i & 1) ans += a[i], a[i] = -a[i];//我是从1开始存的,所以变奇数
			//计算原数组偶数下标和,偶数下标元素值置为原来的相反数方便后面计算
		}
		for (int i = 0; i <= 1; ++ i){//偏移量,分为奇数下标开始和偶数下标开始
			for (int j = i + 1; j < n; j += 2){//i + 1是因为我的数组是从1开始存的
				sum[i] = max(0ll, sum[i] + a[j] + a[j + 1]);
				maxsum = max(sum[i], maxsum);
				//最大子段和,和小于0的段在取max时舍弃
			}
		}
		printf("%lld\n", ans + maxsum);
	}
	return 0;
}

 

你可能感兴趣的:(CodeForces 1373 - D. Maximum Sum on Even Positions - 分类求最大连续子段和 ,思维)