【MX-X19-T3】「LAOI-14」Another Round 解题报告
简要题意
给定 \(n\) 个二元组 \((a_i,b_i)\),有 \(n\) 个询问,第 \(i\) 次询问要求选出 \(i\) 个二元组,使得所有选出的二元组的 \(a\) 的最大值减去 \(b\) 的 \(\operatorname{mex}\)
的值最大。
数据范围:$ n \le 10^6$。
分析
\(a\) 的最大值是可以直接贪心的,关键是怎么处理 \(b\) 的 \(\operatorname{mex}\) 最小。
我们可以枚举 \(b\) 的 \(\operatorname{mex}\)。
我们令 \(cnt_j\) 表示 \(b_i\) 为 \(j\) 的下标 \(i\) 的个数,\(pre_i\) 为 \(\max \limits_{1\le i \le n,b_i \le j}a_i\)。类似地,我们还有 \(suf_i\) 为 \(\max \limits_{1\le i \le n,b_i \ge j}a_i\)。
假设我们枚举 \(\operatorname{mex}\) 为 \(i\)。我们要考虑 \(b\) 小于 \(i\) 的二元组必须选至少一个,\(b\) 等于 \(i\) 的二元组必须不选,其他的选择情况任意。这还是太麻烦了。
于是我们枚举 \(\operatorname{mex}\) 大于等于 \(i\)。这样限制就只有 \(b\) 为 \(i\) 的二元组不能选了。那么在这种情况下我们至多选出 \(n-cnt_i\) 个二元组,答案为 \(mx - i\),其中 \(mx\) 是 \(b\) 不为 \(i\) 的二元组中 \(a\) 最大值。(显然你可以用 \(pre\) 和 \(suf\) 快速求出)由于最大值和 \(\operatorname{mex}\) 已经确定,只要不超过上线选出多少个都可以,所以维护后缀最大值即可。
为什么这么做可以呢?因为这样做求出的 \(\operatorname{mex}\) 是大于等于真实值的,对于一种选择情况,它在枚举到大于等于真实 \(\operatorname{mex}\) 的时候都会被统计,但是被大于真实值的时候被统计得的差值是更小的,而我们又在求差值最大值,所以我们最后得到的 \(\operatorname{mex}\) 一定是最小的。
代码
const int N=1e6+100;
int T,n,ans[N],mx[N],t[N],pre[N],suf[N];
struct Node{int a,b;}a[N];
bool cmp(Node x,Node y){return x.a>y.a || (x.a==y.a && x.b>y.b);}
bool cmp1(Node x,Node y){return x.b>y.b || (x.a==y.a && x.b>y.b);}
bool cmp2(Node x,Node y){return x.b<y.b;}
int vis[N];
void solve(){
n=read();
For(i,1,n) a[i].a=read();
For(i,1,n) a[i].b=read(),ckmn(a[i].b,n+2);
For(i,1,n) ans[i]=-inf;
For(i,0,n+3) t[i]=0,mx[i]=pre[i]=suf[i]=-inf;
For(i,1,n) t[a[i].b]++,ckmx(mx[a[i].b],a[i].a);
pre[0]=mx[0],suf[n+2]=mx[n+2];
For(i,1,n+2) pre[i]=max(pre[i-1],mx[i]);
Down(i,n+1,0) suf[i]=max(suf[i+1],mx[i]);
ckmx(ans[n-t[0]],suf[1]);
int cnt=(t[0] ? 1 : 0);
For(i,1,n+2){
ckmx(ans[n-t[i]],max(pre[i-1],suf[i+1])-cnt);
if(t[i] && cnt==i) ++cnt;
else break;
}
Down(i,n-1,1) ckmx(ans[i],ans[i+1]);
For(i,1,n) printf("%d\n",ans[i]);
}
int main()
{
#if !ONLINE_JUDGE
freopen("test.in","r",stdin);
freopen("test.out","w",stdout);
#endif
T=read();
while(T--) solve();
return 0;
}

浙公网安备 33010602011771号