【题解】arc196_a Adjacent Delete
arc196_a Adjacent Delete
简要题意
给定一个长度为 \(n\) 的数列 \(a\),每次可以选择两个相邻的数字删除,产生的贡献为他们的差,一直删到不能删为止,最大化贡献之和。
\(2\le n\le 3\times 10^5\),\(1\le a_i\le 10^9\)。
题解
知识点:枚举,贪心,STL,对顶堆,主席树。
启发:
-
选相邻两个数操作可能等价于任意选。
-
发掘不出题目性质时,不妨打个暴力自己测几组数据探索一下。
一开始没看到相邻,写了一发贪心上去发现错了,然后看到了相邻,然后就没想过贪心了。
但正解就是贪心,而且有一个非常反直觉的结论:\(n\) 为偶数的时候,相邻选和任意选对这题来说是等价的,至于为什么我交了一发错了,是因为 \(n\) 为奇数的情况没处理好,误打误撞让我卡了很久。
后面在学长的指导下,写了个暴力自己测了几组数据,自己发现了这个结论。
先来理解那个结论为什么是对的:
考虑把前 \(\frac{n}{2}\) 大的数标记为 +,前 \(\frac{n}{2}\) 小标记为 -,那么删数的操作其实就是把相邻 + 和 - 相消,显然在序列非空的时候,一定会有相邻的 + 和 -,那么不管怎么样,最后的贡献都是前 \(\frac{n}{2}\) 大之和减去前 \(\frac{n}{2}\) 小之和。
那么当 \(n\) 为偶数的时候,答案就是前 \(\frac{n}{2}\) 大之和减去前 \(\frac{n}{2}\) 小之和。
而当 \(n\) 为奇数的时候,删到最后会剩下来一个数,那么答案就不能像上面那么计算了。
考虑枚举一个数为最后剩下的数,把它右左边分为两个偶数长度的序列,那么贡献就是左边的加上右边的贡献(计算方式如上),答案就是枚举过程中的最大贡献。
这个过程暴力做是过不了的,要用数据结构来实时维护一个集合中前 \(\frac{n}{2}\) 大之和和前 \(\frac{n}{2}\) 小之和,对顶堆,stl::multiset,主席树等数据结构都能做,但是对顶堆太难调了,当场给我创死了,所以后面写了主席树,调都没调就过了。
#include<bits/stdc++.h>
using namespace std;
#define rep(i,l,r) for(int i=(l);i<=(r);++i)
#define per(i,l,r) for(int i=(r);i>=(l);--i)
#define pr pair<int,int>
#define fi first
#define se second
#define pb push_back
#define all(x) (x).begin(),(x).end()
#define sz(x) (x).size()
#define N 300010
#define ll long long
const int lim=1e9;
int n,a[N],rt[N];
struct HJT{
#define mid ((l+r)>>1)
int cnt=0;
struct node{
int ls,rs,cnt;
ll sum;
}tr[N*41];
inline void ins(int pre,int &k,int l,int r,int d){
k=++cnt;
tr[k]=tr[pre];
tr[k].cnt++;
tr[k].sum+=d;
if(l==r){
return;
}
if(d<=mid){
ins(tr[pre].ls,tr[k].ls,l,mid,d);
}
else{
ins(tr[pre].rs,tr[k].rs,mid+1,r,d);
}
}
inline ll ask_mn(int x,int y,int l,int r,int kth){
if(l==r){
return (long long)kth*l;
}
if(tr[tr[y].ls].cnt-tr[tr[x].ls].cnt<kth){
return tr[tr[y].ls].sum-tr[tr[x].ls].sum+ask_mn(tr[x].rs,tr[y].rs,mid+1,r,kth-(tr[tr[y].ls].cnt-tr[tr[x].ls].cnt));
}
return ask_mn(tr[x].ls,tr[y].ls,l,mid,kth);
}
inline ll ask_mx(int x,int y,int l,int r,int kth){
if(l==r){
return (long long)kth*l;
}
if(tr[tr[y].rs].cnt-tr[tr[x].rs].cnt<kth){
return tr[tr[y].rs].sum-tr[tr[x].rs].sum+ask_mx(tr[x].ls,tr[y].ls,l,mid,kth-(tr[tr[y].rs].cnt-tr[tr[x].rs].cnt));
}
return ask_mx(tr[x].rs,tr[y].rs,mid+1,r,kth);
}
#undef mid
}t;
signed main(){
// freopen(".in","r",stdin);
// freopen(".out","w",stdout);
ios::sync_with_stdio(0);
cin.tie(0);cout.tie(0);
cin>>n;
rep(i,1,n){
cin>>a[i];
t.ins(rt[i-1],rt[i],1,lim,a[i]);
}
if(n%2==0){
ll ans=0;
sort(a+1,a+1+n);
rep(i,1,n/2){
ans+=a[n-i+1]-a[i];
}
cout<<ans<<"\n";
return 0;
}
ll ans=0;
int i=1;
while(i<=n){
ll l=0,r=0;
if(i!=1){
l=t.ask_mx(rt[0],rt[i-1],1,lim,(i-1)/2)-t.ask_mn(rt[0],rt[i-1],1,lim,(i-1)/2);
}
if(i!=n){
r=t.ask_mx(rt[i],rt[n],1,lim,(n-i)/2)-t.ask_mn(rt[i],rt[n],1,lim,(n-i)/2);
}
ans=max(ans,l+r);
i+=2;
}
cout<<ans<<"\n";
return 0;
}

浙公网安备 33010602011771号