A.先放一个2再放一个1,然后全放2,然后全放1即可。
B.f[i][j][k]表示三个串分别匹配到第i,j,k位的最短合法前缀。当某串新增一个字符时,枚举另外两维更新,转移讨论合法前缀的最后一位是哪个字符串的即可。
1 #include<cstdio> 2 #include<cstring> 3 #include<iostream> 4 #include<algorithm> 5 #define rep(i,l,r) for (int i=(l); i<=(r); i++) 6 typedef long long ll; 7 using namespace std; 8 9 const int N=200010,M=300; 10 char op,ch,S[N],S1[M],S2[M],S3[M]; 11 int n,Q,x,s1,s2,s3,nxt[N][30],f[M][M][M]; 12 13 int main(){ 14 scanf("%d%d%s",&n,&Q,S+1); 15 rep(i,0,25) nxt[n+1][i]=nxt[n+2][i]=n+1; 16 for (int i=n; i; i--){ 17 rep(j,0,25) nxt[i][j]=nxt[i+1][j]; 18 nxt[i][S[i]-'a']=i; 19 } 20 rep(i,0,250) rep(j,0,250) rep(k,0,250) f[i][j][k]=n+1; 21 f[0][0][0]=0; 22 while (Q--){ 23 scanf(" %c%d",&op,&x); 24 if (op=='-'){ 25 if (x==1) s1--; 26 if (x==2) s2--; 27 if (x==3) s3--; 28 }else{ 29 scanf(" %c",&ch); 30 if (x==1){ 31 S1[++s1]=ch; 32 rep(i,0,s2) rep(j,0,s3){ 33 int res=nxt[f[s1-1][i][j]+1][ch-'a']; 34 if (i) res=min(res,nxt[f[s1][i-1][j]+1][S2[i]-'a']); 35 if (j) res=min(res,nxt[f[s1][i][j-1]+1][S3[j]-'a']); 36 f[s1][i][j]=min(n+1,res); 37 } 38 } 39 if (x==2){ 40 S2[++s2]=ch; 41 rep(i,0,s1) rep(j,0,s3){ 42 int res=nxt[f[i][s2-1][j]+1][ch-'a']; 43 if (i) res=min(res,nxt[f[i-1][s2][j]+1][S1[i]-'a']); 44 if (j) res=min(res,nxt[f[i][s2][j-1]+1][S3[j]-'a']); 45 f[i][s2][j]=min(n+1,res); 46 } 47 } 48 if (x==3){ 49 S3[++s3]=ch; 50 rep(i,0,s1) rep(j,0,s2){ 51 int res=nxt[f[i][j][s3-1]+1][ch-'a']; 52 if (i) res=min(res,nxt[f[i-1][j][s3]+1][S1[i]-'a']); 53 if (j) res=min(res,nxt[f[i][j-1][s3]+1][S2[j]-'a']); 54 f[i][j][s3]=min(n+1,res); 55 } 56 } 57 } 58 if (f[s1][s2][s3]<=n) puts("YES"); else puts("NO"); 59 } 60 return 0; 61 }
C.直径显然就是某个子串去掉所有可配对括号之后的形如)))(((串的长度,那么线段树维护一堆信息即可。
一种方法是发现最后的式子是与左半部分的左括号、右括号,与右半部分的左括号、右括号数合起来的一个带绝对值的式子。把绝对值拆开讨论即可。
还有一种方法是维护最大/小前/后缀和区间和,然后d维护区间/前缀/后缀内形如))((的最长长度,各种讨论即可。
1 #include<cstdio> 2 #include<algorithm> 3 #define ls (x<<1) 4 #define rs (ls|1) 5 #define lson ls,L,mid 6 #define rson rs,mid+1,R 7 #define rep(i,l,r) for (int i=(l); i<=(r); i++) 8 typedef long long ll; 9 using namespace std; 10 11 const int N=200010; 12 char s[N]; 13 int n,Q,x,y; 14 struct data{ 15 int prex,pren,sufx,sufn,pred,sufd,d,sum,ans; 16 data(){} 17 data(int a,int b,int s,int D,int f,int h,int j,int k,int l){prex=a,pren=b,sufx=s,sufn=D,pred=f,sufd=h,d=j,sum=k,ans=l;} 18 }seg[N<<2],A(1,0,1,0,1,1,1,1,1),B(0,-1,0,-1,1,1,1,-1,1); 19 20 data operator+(const data&a,const data&b){ 21 data s; 22 s.prex=std::max(a.prex,a.sum+b.prex); 23 s.sufx=std::max(b.sufx,b.sum+a.sufx); 24 s.pren=std::min(a.pren,a.sum+b.pren); 25 s.sufn=std::min(b.sufn,b.sum+a.sufn); 26 s.d=std::max(b.d-a.sum,a.d+b.sum); 27 s.pred=std::max(a.pred,std::max(b.pred-a.sum,a.d+b.prex)); 28 s.sufd=std::max(b.sufd,std::max(b.sum+a.sufd,b.d-a.sufn)); 29 s.sum=a.sum+b.sum; 30 s.ans=std::max(std::max(a.ans,b.ans),std::max(b.pred-a.sufn,a.sufd+b.prex)); 31 return s; 32 } 33 34 void build(int x,int L,int R){ 35 if (L==R){ seg[x]=s[L]=='('?A:B; return; } 36 int mid=(L+R)>>1; build(lson); build(rson); 37 seg[x]=seg[ls]+seg[rs]; 38 } 39 40 void mdf(int x,int L,int R,int k){ 41 if (L==R){ seg[x]=s[L]=='('?A:B; return; } 42 int mid=(L+R)>>1; 43 if (k<=mid) mdf(lson,k); else mdf(rson,k); 44 seg[x]=seg[ls]+seg[rs]; 45 } 46 47 int main(){ 48 scanf("%d%d%s",&n,&Q,s+1); n=2*(n-1); build(1,1,n); 49 printf("%d\n",seg[1].ans); 50 while (Q--) scanf("%d%d",&x,&y),swap(s[x],s[y]),mdf(1,1,n,x),mdf(1,1,n,y),printf("%d\n",seg[1].ans); 51 return 0; 52 }