Description
给出一个字符串 s s 以及一个操作串,初始状态 t t 为空串,每次操作要么往的末端加一个字符要么删去 t t 末端的一个字符,操作后查询是否是 s s 的子序列
Input
第一行一个只由小写字母组成的字符串,之后输入一整数 q q 表示操作数,最后行每行一个操作
(1≤|s|,q≤2⋅105) ( 1 ≤ | s | , q ≤ 2 ⋅ 10 5 )
Output
每个操作结束后,如果 t t 是的子序列则输出 YES Y E S ,否则输出 NO N O
Sample Input
abcabc
30
push a
pop
push a
push a
push a
pop
push c
push b
pop
pop
push b
push c
push c
pop
pop
pop
pop
push b
push c
push c
pop
push b
push c
pop
pop
push a
push b
push c
push a
pop
Sample Output
YES
YES
YES
YES
NO
YES
YES
NO
YES
YES
YES
YES
NO
YES
YES
YES
YES
YES
YES
YES
YES
YES
YES
YES
YES
YES
YES
YES
NO
YES
Solution
由于只是判断 t t 是否为的子序列,故贪心的用尽可能 s s 串靠前的字符取匹配,以 Nex[i][j] N e x [ i ] [ j ] 表示 s s 串的第个字符后面第 j j 个字母第一次出现的位置,在匹配过程中记录串的每个字符在 s s 串中的对应匹配位置,每次加入新字符时,考虑之前 t t 串的最后一个字符在串的匹配位置 i i ,如果有合法值那么说明 t t 依旧是的子序列,否则不是
Code
#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<vector>
#include<queue>
#include<map>
#include<set>
#include<ctime>
using namespace std;
typedef long long ll;
typedef pair<int,int>P;
const int INF=0x3f3f3f3f,maxn=200005;
int n,q,Next[maxn][26],pos[26],ans[maxn];
char s[maxn],op[10];
int main()
{
scanf("%s",s+1);
n=strlen(s+1);
memset(Next,-1,sizeof(Next));
memset(pos,-1,sizeof(pos));
for(int i=n;i>=0;i--)
{
for(int j=0;j<26;j++)Next[i][j]=pos[j];
pos[s[i]-'a']=i;
}
scanf("%d",&q);
int m=0,len=0;
ans[0]=0;
while(q--)
{
scanf("%s",op);
if(op[1]=='u')
{
scanf("%s",op);
if(ans[m]!=-1&&Next[ans[m]][op[0]-'a']!=-1)ans[m+1]=Next[ans[m]][op[0]-'a'],m++,len++;
else ans[++m]=-1;
}
else m--,len=min(len,m);
if(len==m)printf("YES\n");
else printf("NO\n");
}
return 0;
}