1 条题解
-
0
这个你考虑枚举所有 作为左端点,怎么求最右边的右端点。令 为前缀和, 为后缀和。
首先可以二分右端点,只要这个区间内所有 就可以,显然这个具有单调性。
现在左边的限制满足了,考虑右边的限制,即满足 。找到 在当前区间内的最小值位置 ,若有多个则取最右的。当 ,那么一定有 。反之,令 则一定满足条件。
这个随便写个 RMQ 就行了。以防空间爆炸,我前缀部分写的 ST 表,后面写的 sgt。
CODE
#include<bits/stdc++.h> using namespace std; //#define int long long int T,n,m; int pre[1001000],suf[1001000]; int st[23][1001000]; int lg[1001000]; int qry(int l,int r){ return min(st[lg[r-l+1]][l],st[lg[r-l+1]][r-(1<<lg[r-l+1])+1]); } int dat[4001000],pos[4001000]; void pushup(int p){ dat[p]=min(dat[p<<1],dat[p<<1|1]); if(dat[p<<1]<dat[p<<1|1]) pos[p]=pos[p<<1]; else pos[p]=pos[p<<1|1]; } void build(int p,int L,int R){ if(L==R){ dat[p]=suf[L];pos[p]=L; return; } int mid=L+R>>1; build(p<<1,L,mid),build(p<<1|1,mid+1,R); pushup(p); } pair<int,int> qry(int p,int L,int R,int l,int r){ if(L>r||R<l) return {0,1e18}; if(L>=l&&R<=r) return {pos[p],dat[p]}; int mid=L+R>>1; pair<int,int> rl=qry(p<<1,L,mid,l,r),rr=qry(p<<1|1,mid+1,R,l,r); if(rl.second<rr.second) return rl; return rr; } signed main(){ ios::sync_with_stdio(0); cin.tie(0),cout.tie(0); cin>>n; for(int i=1;i<=n;i++){ char c; cin>>c; pre[i]=pre[i-1]+(c=='0'?-1:1); st[0][i]=pre[i]; } for(int i=n;i>=1;i--){ suf[i]=suf[i+1]+pre[i]-pre[i-1]; } build(1,1,n); for(int i=2;i<=n;i++){ lg[i]=lg[i/2]+1; } for(int j=1;j<=22;j++){ for(int i=1;i<=n-(1<<j)+1;i++){ st[j][i]=min(st[j-1][i],st[j-1][i+(1<<j-1)]); } } int ans=0; for(int i=1;i<=n;i++){ if(pre[i]-pre[i-1]==1){ int l=i,r=n; while(l<r){ int mid=(l+r+1)>>1; if(qry(i,mid)<pre[i-1]) r=mid-1; else l=mid; } pair<int,int> t=qry(1,1,n,i,l); if(t.second<suf[l+1]) l=t.first-1; ans=max(ans,l-i+1); } } cout<<ans<<'\n'; return 0; }
- 1
信息
- ID
- 708
- 时间
- 1000ms
- 内存
- 256MiB
- 难度
- 10
- 标签
- (无)
- 递交数
- 9
- 已通过
- 2
- 上传者