小 Ad-hoc
对于
n 是偶数
我们的理论最大答案是前
下证一定可以取到。
想象将这前
任何一个中间时刻,序列中一定存在蓝色和红色的数,所以就必定有一对相邻的不同色的数,我们就操作这一对数,因为蓝色的总不小于红色的,所以当前操作合法。问题规模减小,继续做即可。
n 是奇数
肯定恰好有一个元素没有被取到,我们可以证明这个元素下标一定是奇数。(显然,反证,如果它的某一侧元素数量是奇数,那一侧一定删不完)
然后我们就可以枚举这个活下来的数的位置,左右都使用
维护方法是对顶堆,不会的可以学。
代码不短
#include <bits/stdc++.h>
using namespace std;
#define int long long
int n, a[1000005], ans, l[1000005], r[1000005];
set<pair<int, pair<int, int> > > st;
priority_queue<int> q1;
priority_queue<int, vector<int>, greater<int> > q2;
int s1, s2, ans1[1000005], ans2[1000005];
signed main() {
cin >> n;
for (int i = 1; i <= n; i++) {
cin >> a[i];
}
if (1 & ~n) {
sort(a + 1, a + n + 1);
for (int i = 1; i <= n / 2; i++) {
ans -= a[i];
}
for (int i = n / 2 + 1; i <= n; i++) {
ans += a[i];
}
cout << ans << endl;
return 0;
}
q1.push(-2e9);
q2.push(2e9);
for (int i = 1; i <= n; i += 2) {
ans1[i] = s2 - s1;
if (a[i] <= q1.top()) {
s1 += a[i];
q1.push(a[i]);
}
else {
s2 += a[i];
q2.push(a[i]);
}
if (a[i + 1] <= q1.top()) {
s1 += a[i + 1];
q1.push(a[i + 1]);
}
else {
s2 += a[i + 1];
q2.push(a[i + 1]);
}
if (q1.size() > q2.size()) {
s1 -= q1.top();
s2 += q1.top();
q2.push(q1.top());
q1.pop();
}
if (q2.size() > q1.size()) {
s2 -= q2.top();
s1 += q2.top();
q1.push(q2.top());
q2.pop();
}
}
while (!q1.empty()) q1.pop();
while (!q2.empty()) q2.pop();
q1.push(-2e9);
q2.push(2e9);
s1 = s2 = 0;
for (int i = n; i >= 1; i -= 2) {
ans2[i] = s2 - s1;
if (a[i] <= q1.top()) {
s1 += a[i];
q1.push(a[i]);
}
else {
s2 += a[i];
q2.push(a[i]);
}
if (a[i - 1] <= q1.top()) {
s1 += a[i - 1];
q1.push(a[i - 1]);
}
else {
s2 += a[i - 1];
q2.push(a[i - 1]);
}
if (q1.size() > q2.size()) {
s1 -= q1.top();
s2 += q1.top();
q2.push(q1.top());
q1.pop();
}
if (q2.size() > q1.size()) {
s2 -= q2.top();
s1 += q2.top();
q1.push(q2.top());
q2.pop();
}
}
for (int i = 1; i <= n; i += 2) {
ans = max(ans, ans1[i] + ans2[i]);
}
cout << ans << endl;
return 0;
}