【NOIP2021国庆集训Day1】C. 序列修改

【题意】

 

 【分析】

首先,我们可以得到以下结论:

1.将一个数修改为从未出现过的数字一定不优

2.修改第二次出现的数一定不如修改第一次出现的数优

 

有了以上两个结论,我们就可以进行恶心的分类讨论了

 

 

【代码】

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=5e5+5;
const ll inf=1e17;
int n,nxt[maxn];
map <ll,int> G;
ll a[maxn],sum[maxn];
set <ll> s;
bool first[maxn];
ll c1[maxn],c2[maxn];
int lowbit(int x)
{
    return x&(-x);
}
void change1(int x,ll v)
{
    while(x<=n)
    {
        c1[x]=max(c1[x],v);
        x+=lowbit(x);
    }
}
void change2(int x,ll v)
{
    while(x<=n)
    {
        c2[x]=max(c2[x],v);
        x+=lowbit(x);
    }
}
ll query1(int x)
{
    ll res=-inf;
    while(x)
    {
        res=max(res,c1[x]);
        x-=lowbit(x);
    }
    return res;
}
ll query2(int x)
{
    ll res=-inf;
    while(x)
    {
        res=max(res,c2[x]);
        x-=lowbit(x);
    }
    return res;
}
ll b[maxn],del,ans;
int m;
int main()
{
    freopen("sequence.in","r",stdin);
    freopen("sequence.out","w",stdout);
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
        scanf("%lld",&a[i]);
    for(int i=n;i>=1;i--) sum[i]=sum[i+1]+i;
    for(int i=1;i<=n;i++)
    {
        if(!G[a[i]]) first[i]=1,ans+=sum[i],b[++m]=a[i];
        else nxt[G[a[i]]]=i;
        G[a[i]]=i; nxt[i]=n+1;
    }
    s.insert(inf); s.insert(-inf);
    for(int i=1;i<=n;i++)
        if(first[i])
        {
            set<ll>::iterator it = s.lower_bound(a[i]);
            del=min(del,-sum[i]+sum[nxt[i]]+*it-a[i]);
            del=min(del,-sum[i]+sum[nxt[i]]+a[i]-*(--it));
            s.insert(a[i]);
        }
    for(int i=1;i<=n;i++) c1[i]=c2[i]=-inf;
    sort(b+1,b+m+1);
    for(int i=n;i>=1;i--)
    {
        int pos=lower_bound(b+1,b+m+1,a[i])-b;
        del=min(del,sum[nxt[i]]+a[i]-query1(pos));
        del=min(del,sum[nxt[i]]-a[i]-query2(n-pos+1));
        change1(pos,sum[i]+a[i]);
        change2(n-pos+1,sum[i]-a[i]);
    }
    printf("%lld",ans+del);
    return 0;
}

 

posted @ 2021-10-01 21:29  andyc_03  阅读(34)  评论(0编辑  收藏  举报