- 题意:
给定一个数组,设其偶数位置(0, 2, … 2k)上的元素和为sum。我们可以对任意一个子数组,最多逆转一次。计算能得到的最大的sum。 - 思路
首先我们可以想到,如果逆转的子数组length是奇数,则不会有任何变化。
例如 1 2 3 4,逆转长度为3的子数组,可以发现其sum不变。
那么我们便观察,逆转偶数长度的子数组。
例如 7 8 4 5 7 3
我们逆转长度为4的子数组——5 4 8 7 7 3,
可以发现其sum = 5 + 8 + 7,相对于 7 + 4 + 7,变化了(8-7) + (5-4)。
再进行观察,逆转长度为6的子数组——3 7 5 4 8 7
可以发现sum = 3 + 5 + 8, 变化了 (8-7) + (5-4) + (3-7).
因此我们可以发现,对2*x长度的子数组进行逆转,相当于对 x对元素进行逆转,如上述数组 7 8,其位置是0 1,逆转后相对位置变化,对结果做出的贡献是8-7。这样如果从偶数位置开始逆转,偶数位置逆转后成为奇数,其相邻的奇数位置元素逆转成为偶数位置,所以每对元素 对结果做出的贡献是 a[i]-a[i-1],i from 1,i +=2 。
如果是从奇数位置开始逆转,如上述从8开始逆转,其对结果做出的贡献是a[i-1] - a[i],i from 2,i += 2。
这样我们可以得到两种情况。然后每种情况得到一个 n/2取下界长度的数组nums,计算其最大连续和即可。 - 代码:
#include "bits/stdc++.h"
using namespace std;
#define mem(a,b) memset(a,b,sizeof(a))
#define pb push_back
typedef long long ll;
const int maxn = 1e4 + 7;
const int INF =INT_MAX;
const double EPS = 10;
// #define _DEBUG
int main(){
#ifdef _DEBUG
freopen("./Files/in.txt", "r", stdin);
freopen("./Files/out.txt", "w", stdout);
#endif
ios::sync_with_stdio(0);
cin.tie(0);
int t, n;
cin>>t;
while (t--) {
cin>>n;
ll ans = 0, tmp = 0;
ll sum1 = 0, sum2 = 0;
vector<int> a(n, 0);
for(int i = 0;i < n;i++){
cin>>a[i];
if (i % 2 == 0) {
ans += a[i];
}
}
for(int i = 1;i < n;i += 2){
sum1 = max((ll)0, a[i] - a[i-1] + sum1);
tmp = max(tmp, sum1);
}
for(int i = 2;i < n;i += 2){
sum2 = max((ll)0, a[i-1] - a[i] + sum2);
tmp = max(tmp, sum2);
}
ans += tmp;
cout<<ans<<endl;
}
return 0;
}
如第一个循环,a[i]-a[i-1]即nums的值,sum每次加上它,如果小于0,则取sum = 0,也即重新计算连续和。每次tmp更新为最大的sum。
其基本思想就和dp取最大连续和一样。