Educational Codeforces Round 90 D.Maximum Sum on Even Positions

  • 题意:
    给定一个数组,设其偶数位置(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取最大连续和一样。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章