Educational Codeforces Round 102 (Rated for Div. 2) D. Program (思维,前缀和)
- 题意:给你一个只含\(+\)和\(-\)的字符串,给你一个数\(x\),\(x\)初始为\(0\),随着字符串的遍历会加一减一,现在有\(m\)个询问,每个询问给出一个区间\([l,r]\)表示将这个区间内的字符串去除,得到新的字符串,问遍历新字符串后,\(x\)取到的值最多有多少.
- 题解:这题的关键是,\(x\)的值是一一变化的,所以从最大值\(mx\)变为\(mi\),最多有\(mx\)-\(mi\)+1个数,根据题意,区间会把字符串分成两段(不考虑两段的情况),前面的一段很好处理,我们用结构体记录前缀的最小、最大值和前缀和\((l_{mi},l_{mx},l_{full})\),那么我们只要知道后面一段的前缀最小、最大值\((r_{mi},r_{mx})\),那么答案是就是\(max(l_{mx},l_{full}+max(r_{mx},0))-min(l_{mi},l_{full}+min(r_{mi},0))\).关键是后面一段的前缀情况不太容易直观看出来,具体看代码吧.
- 代码:
#include <bits/stdc++.h>
#define ll long long
#define fi first
#define se second
#define pb push_back
#define me memset
#define rep(a,b,c) for(int a=b;a<=c;++a)
#define per(a,b,c) for(int a=b;a>=c;--a)
const int N = 1e6 + 10;
const int mod = 1e9 + 7;
const int INF = 0x3f3f3f3f;
using namespace std;
typedef pair<int,int> PII;
typedef pair<ll,ll> PLL;
ll gcd(ll a,ll b) {return b?gcd(b,a%b):a;}
ll lcm(ll a,ll b) {return a/gcd(a,b)*b;}
int _;
struct misaka{
int mi;
int mx=INF;
int full;
}pre[N];
int main() {
ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
cin>>_;
while(_--){
int n,m;
cin>>n>>m;
string s;
cin>>s;
vector<PII> suf(n+1);
suf[n]={0,0};
pre[0].mi=0;
pre[0].mx=0;
pre[0].full=0;
int mx=0;
int mi=INF;
int cur=0;
rep(i,0,n-1){
cur+=(s[i]=='+')?1:-1;
mx=max(mx,cur);
mi=min(mi,cur);
mi=min(mi,0);
pre[i+1].mi=mi;
pre[i+1].mx=mx;
pre[i+1].full=cur;
}
cur=0;
mx=-INF;
mi=INF;
per(i,n-1,0){
cur=pre[i+1].full;
mx=max(mx,cur);
mi=min(mi,cur);
suf[i].fi=mi-pre[i].full;
suf[i].se=mx-pre[i].full;
//cout<<cur<<' '<<suf[i].fi<<' '<<suf[i].se<<'\n';
}
int l,r;
rep(i,1,m){
cin>>l>>r;
l--,r--;
//cout<<l<<' '<<r<<' '<<pre[l].mi<<' '<<pre[l].mx<<' '<<pre[l].full<<' '<<suf[r+1].fi<<' '<<suf[r+1].se<<'\n';
int _mi=min(pre[l].mi,pre[l].full+suf[r+1].fi);
int _mx=max(pre[l].mx,pre[l].full+suf[r+1].se);
cout<<_mx-_mi+1<<'\n';
}
}
return 0;
}
𝓐𝓬𝓱𝓲𝓮𝓿𝓮𝓶𝓮𝓷𝓽 𝓹𝓻𝓸𝓿𝓲𝓭𝓮𝓼 𝓽𝓱𝓮 𝓸𝓷𝓵𝔂 𝓻𝓮𝓪𝓵
𝓹𝓵𝓮𝓪𝓼𝓾𝓻𝓮 𝓲𝓷 𝓵𝓲𝓯𝓮