题解:P12127 [蓝桥杯 2024 省 B 第二场] 最强小队

· · 题解

更好的阅读体验

感觉比较无脑的一道题,是为了锻炼代码能力才来的。

首先我们知道,如果确定了左右端点 l,r,那么我们就可以得出选出队伍的长度,即 (l,r) 区间中 < \min(l,r) 的数字个数加 2

那么区间左右端点无非就两种情况,a_l < a_ra_l \ge a_r,为了方便可以给第一种情况取个等号。

那么先考虑 a_l \ge a_r 的情况。我们可以枚举右端点,那么区间中的数字要满足的要求就仅和 a_r 的值有关。所以我们就想要让这个区间尽可能大,即找到最小的 i 使 a_i \ge a_r,线段树上二分即可。

对于实现,只需要写一个普通线段树维护区间最小值,再写一个主席树求区间中小于给定数的元素数量。那么就 $O(n \log^2 n)$ 的复杂度做完了,如果把二分搬到线段树上可以轻松一只 $\log$,但懒得写。 ```cpp #include<bits/stdc++.h> #define int long long #define endl '\n' #define N 100006 using namespace std; int n,a[N],b[N],bn,ans; struct Segtree{int tree[N<<2]; void build(int p,int l,int r) { if(l==r)return tree[p]=a[l],(void)0; int mid=l+r>>1; build(p<<1,l,mid),build(p<<1|1,mid+1,r); tree[p]=max(tree[p<<1],tree[p<<1|1]); } int query(int p,int l,int r,int L,int R) { if(L<=l&&r<=R)return tree[p]; int mid=l+r>>1,ret=-1e15; if(L<=mid)ret=max(ret,query(p<<1,l,mid,L,R)); if(R>mid)ret=max(ret,query(p<<1|1,mid+1,r,L,R)); return ret; }}T1; struct HJTtree{int tot,rt[N]; struct Node{int ls,rs,sum;}tree[N<<5]; void update(int &p,int q,int l,int r,int k) { tree[p=++tot]=tree[q],tree[p].sum++; if(l==r)return;int mid=l+r>>1; if(k<=mid)update(tree[p].ls,tree[q].ls,l,mid,k); else update(tree[p].rs,tree[q].rs,mid+1,r,k); } int query(int p,int q,int l,int r,int L,int R) { if(L>R)return 0; if(L<=l&&r<=R)return tree[p].sum-tree[q].sum; int mid=l+r>>1,ret=0; if(L<=mid)ret+=query(tree[p].ls,tree[q].ls,l,mid,L,R); if(R>mid)ret+=query(tree[p].rs,tree[q].rs,mid+1,r,L,R); return ret; }}T2; main() { scanf("%lld",&n); for(int i=1;i<=n;i++) scanf("%lld",&a[i]),b[++bn]=a[i]; if(n==1)return printf("1\n"),0; sort(b+1,b+1+bn),bn=unique(b+1,b+1+bn)-b-1; for(int i=1;i<=n;i++) a[i]=lower_bound(b+1,b+1+bn,a[i])-b; T1.build(1,1,n); for(int i=1;i<=n;i++) T2.update(T2.rt[i],T2.rt[i-1],1,bn,a[i]); for(int i=2;i<=n;i++) { int l=1,r=i-1,pos=0; while(l<=r) { int mid=l+r>>1; if(T1.query(1,1,n,1,mid)<a[i]) pos=mid,l=mid+1; else r=mid-1; } pos++,ans=max(ans,T2.query(T2.rt[i-1],T2.rt[pos],1,bn,1,a[i]-1)+2); } for(int i=1;i<n;i++) { int l=i+1,r=n,pos=n+1; while(l<=r) { int mid=l+r>>1; if(T1.query(1,1,n,mid,n)<a[i]) pos=mid,r=mid-1; else l=mid+1; } pos--,ans=max(ans,T2.query(T2.rt[pos-1],T2.rt[i],1,bn,1,a[i]-1)+2); } printf("%lld\n",ans); return 0; } ```