题目链接: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 << " "; } int main() { int t; cin >> t; while (t--) solve(); }