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<<'
';
		}

		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<<'
';
			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<<'
';
		}
	}

    return 0;
}
原文地址:https://www.cnblogs.com/lr599909928/p/14342792.html