传送门
考虑二分答案,假设答案为
k
k
k,那么如何取check呢?我们可以从左到右贪心的选
l
1
,
l
2
,
l
3
.
.
.
l
k
l_1,l_2,l_3...l_k
l1,l2,l3...lk代表左边最近的
k
k
k个2的位置,然后对于每个2我们都贪心地选一个右边离它最近的位置的0进行配对,这些配对的0的位置分别是
r
1
,
r
2
,
r
3
.
.
.
r
k
r_1,r_2,r_3...r_k
r1,r2,r3...rk,很显然满足
l
1
<
l
2
<
.
.
.
<
l
k
,
r
1
<
r
2
<
.
.
.
r
k
,
l
i
<
r
i
l_1<l_2<...<l_k,r_1<r_2<...r_k,l_i<r_i
l1<l2<...<lk,r1<r2<...rk,li<ri,然后我们再从右边到左边贪心的选
k
k
k个离右边最近的0,按从右到左的顺序存到
r
2
k
,
r
2
k
−
1
,
.
.
.
,
r
k
+
1
r_{2k},r_{2k-1},...,r_{k+1}
r2k,r2k−1,...,rk+1,对于每个0而言同样选择左边离它最近的2,存到
l
2
k
,
l
2
k
−
1
,
.
.
.
,
l
k
+
1
l_{2k},l_{2k-1},...,l_{k+1}
l2k,l2k−1,...,lk+1中,这样子的话我们可以让
(
l
i
,
r
i
)
(l_i,r_i)
(li,ri)与
(
l
i
+
k
,
r
i
+
k
)
(l_{i+k},r_{i+k})
(li+k,ri+k)配对形成2020,如果无法形成配对,即满足
r
i
≥
l
i
+
k
r_i\ge l_{i+k}
ri≥li+k或
l
1
∼
k
,
r
1
∼
k
l_{1\sim k},r_{1\sim k}
l1∼k,r1∼k与
l
k
+
1
∼
2
k
,
r
k
+
1
∼
2
k
l_{k+1\sim 2k},r_{k+1\sim 2k}
lk+1∼2k,rk+1∼2k存在交集的话,说明在答案为
k
k
k的情况下是无法配对出足够数量的
2020
2020
2020的。
以上贪心显然是正确的。
char s[maxn];
int n,mi[maxn],mx[maxn],vis[maxn];
bool check(int k){
int tot1=0,tot2=0;
memset(vis,0,sizeof(int)*n);
FOR(i,0,n){
if(s[i]=='2' && tot1<k)mi[++tot1]=i;else if(s[i]=='0' && tot2<tot1)mx[++tot2]=i;
if(tot1==k && tot2==k)break;
}
if(tot1!=k || tot2!=k)return false;
tot1=0,tot2=0;
ROF(i,n-1,0){
if(s[i]=='0' && tot1<k)mx[(k<<1)-(tot1++)]=i;else if(s[i]=='2' && tot2<tot1)mi[(k<<1)-(tot2++)]=i;
if(tot1==k && tot2==k)break;
}
if(tot1 !=k || tot2!=k)return false;
FOR(i,1,k+1){
if(mx[i]>=mi[i+k] || vis[mi[i]] || vis[mx[i]])return false;
vis[mi[i+k]]=vis[mx[i+k]]=1;
}
return true;
}
int main(){
while(~scanf("%d",&n)){
scanf("%s",s);
int ans=0,l=1,r=n;
while(l<=r){
int mid=l+r>>1;
if(ans==mid || check(mid)){
ans=mid;
l=mid+1;
}else r=mid-1;
}
wrn(ans);
}
}