- 題意:
給定一個數組,設其偶數位置(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取最大連續和一樣。