题意
https://vjudge.net/problem/CodeForces-1263E
您要设计一个只有一行的打字机,这一行的长度是无限大,一开始可以认为每个字符都是空。您的打字机有一个光标只指向一个字符,一开始指向最左侧的字符。
使用者有三种操作:
- L 将光标向左移一格(当光标已经在最左侧时,忽略这次操作)
- R 将光标向右移一格
- 一个小写字符或者‘(‘,‘)‘ 将当前字符替换为给定字符
您需要在每次操作后,判断这一行是否是合法括号序列(例如 (ahakioi)
就是合法的,(ige))(tscore
就是非法的),不是输出 -1
,否则输出最多嵌套数(例如 ()(())()()
的最多嵌套数是 2,(()(()())())(())
的最多嵌套数是 3)。
思路
看上去是个大模拟,实则是个线段树的技巧题。
用一个pos记录光标的位置。
记‘(‘为1,‘)‘为-1,其他字符为0,这样如果有某个前缀和<0(只用判断前缀和最小值<0即可),那么就不合法,或者所有加起来不等于0,也不合法。
单点更新,维护区间和sum,前缀和最小值mn,前缀和最大值mx。区间前缀和最小值和左右子树有关,比较左子树的前缀和最小值、右子树的前缀和最小值+左子树的区间和,用小的那个更新mn[rt],前缀和最大值同理。
那么在合法的情况下,前缀和的最大值即为最多嵌套数。
代码
#include<bits/stdc++.h> using namespace std; #define inf 0x3f3f3f3f #define ll long long const int N=1e6+5; const double eps=1e-8; const double PI = acos(-1.0); #define lowbit(x) (x&(-x)) int sum[N<<2],mn[N<<2],mx[N<<2],n; void pushUp(int rt) { sum[rt]=sum[rt<<1]+sum[rt<<1|1]; mn[rt]=min(mn[rt<<1],mn[rt<<1|1]+sum[rt<<1]); mx[rt]=max(mx[rt<<1],mx[rt<<1|1]+sum[rt<<1]); } void update(int L,int C,int l,int r,int rt) { if(l==r) { sum[rt]=mn[rt]=mx[rt]=C; return; } int m=(l+r)>>1; if(L <= m) update(L,C,l,m,rt<<1); else update(L,C,m+1,r,rt<<1|1); pushUp(rt); } int main() { std::ios::sync_with_stdio(false); cin>>n; string s; cin>>s; int pos=1,r=1,ans=0; for(int i=0; i<n; i++) { char c=s[i]; if(c==‘R‘) pos++; else if(c==‘L‘) { if(pos>1) pos--; } else { if(c==‘(‘) update(pos,1,1,n,1); else if(c==‘)‘) update(pos,-1,1,n,1); else update(pos,0,1,n,1); } if(sum[1]!=0||mn[1]<0) { cout<<-1<<" "; } else cout<<mx[1]<<" "; } cout<<endl; return 0; }
原文地址:https://www.cnblogs.com/mcq1999/p/11980420.html
时间: 2024-10-13 16:21:42