​Link​

注意到任何时刻 s 1 , s 2 , s 3 s_1,s_2,s_3 s1​,s2​,s3​的长度不会多于 250 250 250

那么定义 f [ i ] [ j ] [ k ] f[i][j][k] f[i][j][k]表示当三个串分别匹配到 i , j , k i,j,k i,j,k位置时,匹配到 S S S串的最左端位置

这个预处理一个 n x t [ i ] [ j ] nxt[i][j] nxt[i][j]数字就很好转移了,表示 [ i + 1 , n ] [i+1,n] [i+1,n]中最早出现字母 j j j的位置

如果串 s 1 , s 2 , s 3 s_1,s_2,s_3 s1​,s2​,s3​确定,这个 f f f数组可以很容易处理出来

现在动态在末尾加入一个字符

多出来的状态最多只有 25 0 2 250^2 2502个,可以暴力跑 D P DP DP

在末尾删去一个数字,就直接删除就好了

#include <bits/stdc++.h>
using namespace std;
const int inf = 1e9;
const int maxn = 4e5+10;
int n,q,nxt[maxn][28],f[253][253][253];
char a[maxn],s[4][maxn];
int id[4];
void DP(int i,int j,int k)
{
if( i==j && j==k && i==0 ) { f[0][0][0] = 0; return; }
f[i][j][k] = n+1;
int q = s[1][i]-'a', w = s[2][j]-'a', e = s[3][k]-'a';
if( i ) f[i][j][k] = min( f[i][j][k], nxt[ f[i-1][j][k] ][q] );
if( j ) f[i][j][k] = min( f[i][j][k], nxt[ f[i][j-1][k] ][w] );
if( k ) f[i][j][k] = min( f[i][j][k], nxt[ f[i][j][k-1] ][e] );
}
int main()
{
cin >> n >> q >> ( a+1 );
for(int i=0;i<=25;i++) nxt[n][i] = nxt[n+1][i] = nxt[n+2][i] = n+1;
for(int i=n-1;i>=0;i--)
{
for(int j=0;j<=25;j++) nxt[i][j] = nxt[i+1][j];
nxt[i][a[i+1]-'a'] = i+1;
}
while( q-- )
{
string type,C; int num; cin >> type;
if( type[0]=='+' )//增加
{
cin >> num >> C;
id[num]++; s[num][id[num]] = C[0];
int l = id[num];
if( num==1 )
{
for(int i=0;i<=id[2];i++)
for(int j=0;j<=id[3];j++)
DP(l,i,j);
}
else if( num==2 )
{
for(int i=0;i<=id[1];i++)
for(int j=0;j<=id[3];j++)
DP(i,l,j);
}
else
{
for(int i=0;i<=id[1];i++)
for(int j=0;j<=id[2];j++)
DP(i,j,l);
}
}
else//减少
{
cin >> num;
id[num]--;
}
if( f[id[1]][id[2]][id[3]]<=n ) cout << "YES\n";
else cout << "NO\n";
}
}