970. 序列和

#970. 序列和

给定一个长度为 \(n\) 序列\(a0,a1,…,an−1\) ,你可以翻转它的一个连续子段(可以为空) , 使得所有偶数下标的数字之和最大。

输入格式

第一行一个整数\(n\) , 表示序列的长度。\((1≤n≤2×10^5)\)

第二行 \(n\) 个整数 \(a0,a1,…,an−1\) 表示序列 \(a\)\((1≤ai≤10^9)\)

输出格式

输出一个整数表示偶数下标之和的最大值。

样例输入

8
1 7 3 4 7 6 2 9

样例输出

26

题目解析

为方便说明,默认序列开头为1。令\(sum[i]\)\(a[1]——a[i]\)中下标奇偶性和自身一致的数的前缀合

由于输出下标是奇数,对于答案选定区间,分两种情况讨论:

  • 如果选定区间末尾\(r\)是偶数,区间左边\(l\)一定是奇数,则\(ans+=sum[r]-sum[r-1]-(sum[l-1]-sum[l-2])\) //偶数
  • 选定区间末尾是奇数\(r\),左边\(l\)是偶数,则\(ans+=sum[l-1]-sum[l-2]-(sum[r]-sum[r-1])\) //奇数

那么,我们将\(sum[i]-sum[i-1]\)根据奇偶性合并成两个新数组,然后分别求出前大后小、前小后大的序列差即可。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 2e5+7;
ll a[N],sum[N];
vector<ll>x[2];
ll find1() {//左小右大 
	vector<ll>a = x[0];
	ll minn = a[0], maxnn = a[0], t = a[0], ans = 0;
	for(int i = 0 ; i < a.size() ; i++) {
		maxnn = max(maxnn,a[i]);
		t = min(t,a[i]);
		if(a[i]-t>maxnn - minn) {
			maxnn = a[i];
			minn = t;
		}
		ans = max(ans,maxnn-minn);
	}
	return ans;
}
ll find2() {//左大右小 
	vector<ll>a = x[1];
	ll minn = a[0], maxnn = a[0], t = a[0], ans = 0;
	for(int i = 0 ; i < a.size() ; i++) {
		minn = min(minn,a[i]);
		t = max(t,a[i]);
		if(t-a[i]<maxnn - minn) {
			maxnn = t;
			minn = a[i];
		}
		ans = max(ans,maxnn-minn);
	}
	return ans;
}
int main() {
	int n;
	scanf("%d",&n);
	ll ans = 0, maxn = 0;
	for(int i = 1 ; i <= n ; i++) {
		scanf("%lld",&a[i]);
	}
	for(int i = 1 ; i <= n ; i++) {
		if(i!=1)
			sum[i] += sum[i-2];
		sum[i] += a[i];
	}
	if(n%2)
		ans = sum[n];
	else ans = sum[n-1];
	x[0].push_back(0);

	for(int i = 1 ; i <= n ; i++) {
		x[i%2].push_back(sum[i]-sum[i-1]);
	}
	maxn = max({0ll,find1(),find2()});
	cout << ans+maxn;
}
posted @ 2022-05-31 17:16  seekerHeron  阅读(39)  评论(0)    收藏  举报