【题解】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;
}
posted @ 2025-04-07 20:25  Lucyna_Kushinada  阅读(29)  评论(0)    收藏  举报