CF2018D Max Plus Min Plus Size 题解

· · 题解

思路

我们充分发扬人类智慧。

注意到想要让答案最大,那么 a_i 最大的那几个有极大概率会被选。

于是我们只需要枚举前 100 个最大的 a_i 为最大值,钦定其必须选,剩下的跑暴力并查集算贡献即可。

code

代码非常短。

#include<bits/stdc++.h>
using namespace std;
using ll=long long;
int const maxn=200000;
int T;
int n;
int a[maxn+1];
int b[maxn+1];
int fa[maxn+1];
int siz[maxn+1];
int find(int a){
    if(fa[a]==a){
        return a;
    }
    return fa[a]=find(fa[a]);
}
void merge(int u,int v,int &sum){
    u=find(u);
    v=find(v);
    if(u==v){
        return;
    }
    if(siz[v]<siz[u]){
        swap(u,v);
    }
    sum-=(siz[u]+1)/2;
    sum-=(siz[v]+1)/2;
    fa[u]=v;
    siz[v]+=siz[u];
    siz[u]=0;
    sum+=(siz[v]+1)/2;
}
void sol(){
    cin>>n;
    for(int i=1;i<=n;i++){
        cin>>a[i];
        b[i]=i;
    }
    sort(b+1,b+n+1,[](int x,int y){
        return a[x]<a[y];
    });
    int ans=0;
    for(int i=1;i<=n;i++){
        fa[b[i]]=0;
        siz[b[i]]=0;
    }
    for(int p=max(n-100,1);p<=n;p++){
        int sum=1;
        for(int i=1;i<=p;i++){
            fa[b[i]]=0;
            siz[b[i]]=0;
        }
        ans=max(ans,a[b[p]]+a[b[p]]+1);
        for(int i=p-1;i>=1;i--){
            int g=b[i];
            if(g==b[p]-1||g==b[p]+1){
                continue;
            }
            fa[g]=g;
            siz[g]=1;
            sum++;
            if(g>1&&fa[g-1]!=0){
                merge(g-1,g,sum);
            }
            if(g<n&&fa[g+1]!=0){
                merge(g+1,g,sum);
            }
            ans=max(ans,a[g]+sum+a[b[p]]);
        }
    }
    cout<<ans<<"\n";
}
signed main(){
    ios::sync_with_stdio(0);
    cin.tie(0);
    cin>>T;
    while(T--){
        sol();
    }

    return 0;
}