Educational Codeforces Round 90 (Rated for Div. 2) D. Maximum Sum on Even Positions(dp)

题目链接:https://codeforces.com/contest/1373/problem/D

题意

给出一个大小为 $n$ 的数组 $a$,下标为 $0 \sim n - 1$,可以进行一次反转一个区间中元素的操作,问偶数下标元素的最大和,

题解

如果反转区间长度为奇数,则下标奇偶性不同的元素间不会互换,所以反转的区间长度为偶数,反转后的区间可以看作相邻元素两两交换所得。

如:1 2 3 4 反转后为 4 3 2 1,偶数下标元素由 1 3 变成了 2 4 ,可以看作 1 与 2 相交换,3 与 4 相交换。

枚举反转区间左端点的奇偶性:

  • 左端点为偶数,对于每个子区间 [i, i + 1],反转后的收益为 $a_{i +1} - a_i$
  • 左端点为奇数,对于每个子区间 [i, i + 1],反转后的收益为 $a_{i} - a_{i+1}$

所需反转的总区间即为加起来收益最大的一些连续子区间。

代码

#include <bits/stdc++.h>
using ll = long long;
using namespace std;

void solve() {
    int n; cin >> n;
    int a[n] = {};
    for (int i = 0; i < n; i++)
        cin >> a[i];
    ll mx = 0, al = 0, ar = 0;
    for (int st : {0, 1}) { //枚举反转区间左端点的奇偶性
        ll sum = 0, l = st, r = st; // sum 是以当前子区间结尾的最大收益,[l, r] 是该最大收益所在的区间
        for (int i = st; i + 1 < n; i += 2) {
            int val = (st == 0 ? a[i + 1] - a[i] : a[i] - a[i + 1]); //当前子区间的收益
            if (sum > 0) { //如果之前区间的收益大于0
                sum += val;
                r = i + 1;
            } else {
                sum = val;
                l = i; 
                r = i + 1;
            }
            if (sum > mx) {
                mx = sum; 
                al = l, ar = r;
            }
        }
    }
    reverse(a + al, a + ar + 1);
    ll ans = 0;
    for (int i = 0; i < n; i += 2)
        ans += a[i];
    cout << ans << "\n";
}

int main() {
    int t; cin >> t;
    while (t--) solve();
}

 

posted @ 2020-06-27 00:20  Kanoon  阅读(95)  评论(0编辑  收藏  举报