原题
题目描述
この問題における 11/22 文字列の定義は A 問題および C 問題と同じです。
文字列 $ T $ が以下の条件を全て満たすとき、$ T $ を 11/22 文字列 と呼びます。
- $ |T| $ は奇数である。ここで、$ |T| $ は $ T $ の長さを表す。
- $ 1 $ 文字目から $ \frac{|T|+1}{2}\ -\ 1 $ 文字目までが
1
である。 - $ \frac{|T|+1}{2} $ 文字目が
/
である。 - $ \frac{|T|+1}{2}\ +\ 1 $ 文字目から $ |T| $ 文字目までが
2
である。
例えば 11/22
, 111/222
, /
は 11/22 文字列ですが、1122
, 1/22
, 11/2222
, 22/11
, //2/2/211
はそうではありません。
1
, 2
, /
からなる長さ $ N $ の文字列 $ S $ が与えられるので、$ Q $ 個のクエリを処理してください。
各クエリでは $ L $, $ R $ が与えられます。$ S $ の $ L $ 文字目から $ R $ 文字目までからなる (連続な) 部分文字列を $ T $ としたとき、 11/22 文字列であるような $ T $ の (連続とは限らない) 部分列の長さの最大値を求めてください。そのような部分列が存在しないときは 0
を出力してください。
输入格式
入力は以下の形式で標準入力から与えられる。ここで $ \mathrm{query}_i $ は $ i $ 番目のクエリを意味する。
$ N $ $ Q $ $ S $ $ \mathrm{query}_1 $ $ \mathrm{query}_2 $ $ \vdots $ $ \mathrm{query}_Q $
各クエリは以下の形式で与えられる。
$ L $ $ R $
输出格式
$ Q $ 行出力せよ。$ i $ 行目には $ i $ 番目のクエリへの答えを出力せよ。
输入输出样例 #1
输入 #1
12 5
111/212/1122
1 7
9 12
3 6
4 10
1 12
输出 #1
5
0
3
1
7
说明/提示
制約
- $ 1\ \leq\ N\ \leq\ 10^5 $
- $ 1\ \leq\ Q\ \leq\ 10^5 $
- $ S $ は
1
,2
,/
からなる長さ $ N $ の文字列 - $ 1\ \leq\ L\ \leq\ R\ \leq\ N $
- $ N,\ Q,\ L,\ R $ は整数
Sample Explanation 1
$ 1 $ 番目のクエリについて、$ S $ の $ 1 $ 文字目から $ 7 $ 文字目からなる部分文字列は 111/212
です。この文字列は 11/22
を部分列として含み、これは 11/22 文字列であるような部分列として最大です。よって答えは $ 5 $ です。 $ 2 $ 番目のクエリについて、$ S $ の $ 9 $ 文字目から $ 12 $ 文字目からなる部分文字列は 1122
です。この文字列は 11/22 文字列であるような部分列を含まないので、答えは $ 0 $ です。
思路
可以发现对于任意一条杠,要想使对于这条杠最大,是直接将左边的全部 1 1 1 与右边全部的 2 2 2 取最小 × 2 + 1 \times2+1 ×2+1。
那么我们可以对 1 1 1 的个数与 2 2 2 的个数求一个前缀和。然后用二分对每一次询问求最左边的杠与最右边的杠,然后再用二分求最大。再来说一下求值的二分的具体方法。可以发现,如果 1 1 1 的个数少,肯定尽量往后靠,使得平均。 2 2 2 少时方法也一样,即往前靠,使得平均。我的写法是把三个二分和在一起,就不多介绍了。
Code
cpp
#include<bits/stdc++.h>
using namespace std;
int n,m,gang[1145140],sum1[1145140],sum2[1145140],id;
string s;
int main(){
cin>>n>>m;
cin>>s;
s=' '+s;
for(int i=1;i<=n;i++){
if(s[i]=='/'){
id++;
gang[id]=i;
}
sum1[i]=sum1[i-1]+(s[i]=='1');
sum2[i]=sum2[i-1]+(s[i]=='2');
}
while(m--){
int l,r;
cin>>l>>r;
int li=1,ri=id,ans=0;
while(li<=ri){
int mid=(li+ri)/2;
if(gang[mid]<l){
li=mid+1;
continue;
}
if(gang[mid]>r){
ri=mid-1;
continue;
}
int p1=sum1[gang[mid]]-sum1[l-1];
int p2=sum2[r]-sum2[gang[mid]-1];
if(p1<=p2){
li=mid+1;
}
else{
ri=mid-1;
}
ans=max(ans,2*min(p1,p2)+1);
}
cout<<ans<<endl;
}
return 0;
}