【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; }