1. 程式人生 > >NOI模擬:必去之

NOI模擬:必去之

在這裡插入圖片描述

題解: fi=maxj{min{aiaj,bibj}+fj+1}(j<i,pj<i)f_i = \max_j \{\min \{a_i-a_j,b_i-b_j\}+f_j+1\} (j \lt i, p_j \lt i) 其中aia_i為沒有填的數中比pip_i小的數,bb為字首0的個數。

CDQ分治+樹狀陣列解決三維偏序。

#include <bits/stdc++.h>
using namespace std;

const
int RLEN=1<<18|1; inline char nc() { static char ibuf[RLEN],*ib,*ob; (ib==ob) && (ob=(ib=ibuf)+fread(ibuf,1,RLEN,stdin)); return (ib==ob) ? -1 : *ib++; } inline int rd() { char ch=nc(); int i=0,f=1; while(!isdigit(ch)) {if(ch=='-')f=-1; ch=nc();} while(isdigit(ch)) {i=(i<<1
)+(i<<3)+ch-'0'; ch=nc();} return i*f; } const int N=1e5+50, L=1e5+2, INF=0x3f3f3f3f; int n,m,ans; int p[N],a[N],b[N],f[N]; int bit[2][N*2]; inline void inc_up(int *bit,int p,int val) {for(p+=L;p<=2*L;p+=p&(-p)) bit[p]=max(bit[p],val);} inline void inc_down(int *bit,int p,int val) {for(
p+=L;p;p-=p&(-p)) bit[p]=max(bit[p],val);} inline int ask_up(int *bit,int p,int rs=-INF) {for(p+=L;p<=2*L;p+=p&(-p)) rs=max(rs,bit[p]); return rs;} inline int ask_down(int *bit,int p,int rs=-INF) {for(p+=L;p;p-=p&(-p)) rs=max(rs,bit[p]); return rs;} inline void del_up(int *bit,int p) {for(p+=L;p<=2*L;p+=p&(-p)) bit[p]=-INF;} inline void del_down(int *bit,int p) {for(p+=L;p;p-=p&(-p)) bit[p]=-INF;} inline void solve(int l,int r) { if(l==r) return; int mid=(l+r)>>1; solve(l,mid); vector <int> op; for(int i=l;i<=r;i++) if(i==0 || p[i]) op.push_back(i); sort(op.begin(),op.end(),[&](const int &i,const int &j) {return p[i]<p[j];}); for(auto i:op) { if(i<=mid) { inc_down(bit[0],a[p[i]]-b[i],f[i]-a[p[i]]); inc_up(bit[1],a[p[i]]-b[i],f[i]-b[i]); } else { f[i]=max(f[i],ask_up(bit[0],a[p[i]]-b[i])+a[p[i]]+1); f[i]=max(f[i],ask_down(bit[1],a[p[i]]-b[i])+b[i]+1); } } for(auto i:op) if(i<=mid) del_down(bit[0],a[p[i]]-b[i]), del_up(bit[1],a[p[i]]-b[i]); solve(mid+1,r); } int main() { n=rd(); m=n; for(int i=1;i<=2*L;i++) bit[0][i]=bit[1][i]=-INF; for(int i=1;i<=n;i++) a[i]=1; for(int i=1;i<=n;i++) p[i]=rd(), (p[i] && (--m,--a[p[i]])); for(int i=1;i<=n;i++) a[i]+=a[i-1]; for(int i=1;i<=n;i++) b[i]=b[i-1]+(!p[i]); p[0]=0; solve(0,n); for(int i=0;i<=n;i++) if(i==0 || p[i]) ans=max(ans,f[i]+min(m-a[p[i]],m-b[i])); cout<<ans<<'\n'; }