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;
}

浙公网安备 33010602011771号