D. Program
大致题意:
给你一个长为n的字符串 由‘+’、‘-’组成,初始值x=0,遇到+就+1,遇到-就-1。
给你m个询问,每一个询问存在两个整数l,r,问如果省略掉字符串中[l,r]的字符,x的不同值有多少个。
思路:
首先,无论省略哪一块,x取值一定是连续的(原因:±1操作)。所以如果能知道最大值最小值,两者相减+1即可。
其次,对于一连串操作,任何数经过这些操作所改变的上下起伏是一样的。
所以:
对于最大值:在下标l之前的x最大值和r之后的所有操作起伏加上a[l-1]中取最大值。
对于最小值:在下标l之前的x最小值和r之后的所有操作起伏加上a[l-1]中取最小值。
代码:
#include<algorithm>
#include<iostream>
#include<cstring>
#include<string>
#include<queue>
#include<map>
#include<cstdio>
#include<cmath>
#include<stdlib.h>
using namespace std;
typedef long long ll;
const int INF = 0x3f3f3f3f;
const int maxn = 2e5+50;
int a[maxn];
int pmax[maxn],pmin[maxn];
int smax[maxn],smin[maxn];
void solve(){
string s;
int n,m;
cin >> n >> m;
cin >> s;
int x = 0;
a[0] = 0;
//a[i]表示经过前i个字符后x的值
for(int i = 0;i < n;i++){
if(s[i] == '+') x++;
else x--;
a[i+1] = x;
}
pmax[0] = pmin[0] = 0;//未经过操作 初始值为0
smax[n+1] = -INF;smin[n+1] = INF;//临界 不会到此处 初始化为相应极值
for(int i = 1;i <= n;i++){
pmax[i] = max(pmax[i-1],a[i]);
pmin[i] = min(pmin[i-1],a[i]);
}
for(int i = n;i >= 1;i--){
smax[i] = max(smax[i+1],a[i]);
smin[i] = min(smin[i+1],a[i]);
}
int l,r;
while(m--){
cin >> l >> r;
int ans = 0;
int lmax = pmax[l-1],lmin = pmin[l-1];
int rmax = smax[r+1],rmin = smin[r+1];
if(r == n){//r在最后 起伏为0 直接lmax-lmin+1即可
ans = lmax-lmin+1;
cout << ans << endl;
continue;
}
int max_up = rmax-a[r],max_down = a[r]-rmin;//向上向下起伏波动
int rm = max(lmax,a[l-1]+max_up);
int lm = min(lmin,a[l-1]-max_down);
ans = rm-lm+1;
cout << ans << endl;
}
}
int main(){
int t;
cin >> t;
while(t--){
solve();
}
return 0;
}