大意: 给定字符串S, 要求维护三个串, 支持在每个串末尾添加或删除字符, 询问S是否能找到三个不相交的子序列等于三个串.
暴力DP, 若不考虑动态维护的话, 可以直接$O(len^3)$处理出最少需要S中前多少位能匹配.
考虑添加删除的话, DP刷表, $O(len^2q)$
#include <iostream> #include <iostream> #include <algorithm> #include <cstdio> #include <math.h> #include <set> #include <map> #include <queue> #include <string> #include <string.h> #include <bitset> #define REP(i,a,n) for(int i=a;i<=n;++i) #define PER(i,a,n) for(int i=n;i>=a;--i) #define hr putchar(10) #define pb push_back #define lc (o<<1) #define rc (lc|1) #define mid ((l+r)>>1) #define ls lc,l,mid #define rs rc,mid+1,r #define x first #define y second #define io std::ios::sync_with_stdio(false) #define endl ' ' #define DB(a) ({REP(__i,1,n) cout<<a[__i]<<' ';hr;}) using namespace std; typedef long long ll; typedef pair<int,int> pii; const int P = 1e9+7, INF = 0x3f3f3f3f; ll gcd(ll a,ll b) {return b?gcd(b,a%b):a;} ll qpow(ll a,ll n) {ll r=1%P;for (a%=P;n;a=a*a%P,n>>=1)if(n&1)r=r*a%P;return r;} ll inv(ll x){return x<=1?1:inv(P%x)*(P-P/x)%P;} inline int rd() {int x=0;char p=getchar();while(p<'0'||p>'9')p=getchar();while(p>='0'&&p<='9')x=x*10+p-'0',p=getchar();return x;} //head const int N = 1e5+10, M = 300; int n, q; char s[N], a[4][M]; int dp[M][M][M], nxt[N][27], len[4]; void upd(int x) { REP(i,x==1?len[1]:0,len[1]) { REP(j,x==2?len[2]:0,len[2]) { REP(k,x==3?len[3]:0,len[3]) { int &r = dp[i][j][k] = n+2; if (i&&dp[i-1][j][k]+1<=n) r=min(r,nxt[dp[i-1][j][k]+1][a[1][i]-'a']); if (j&&dp[i][j-1][k]+1<=n) r=min(r,nxt[dp[i][j-1][k]+1][a[2][j]-'a']); if (k&&dp[i][j][k-1]+1<=n) r=min(r,nxt[dp[i][j][k-1]+1][a[3][k]-'a']); } } } } int main() { scanf("%d%d%s", &n, &q, s+1); REP(i,'a','z') { nxt[n+1][i-'a']=n+2; PER(j,1,n) { if (s[j]==i) nxt[j][i-'a']=j; else nxt[j][i-'a']=nxt[j+1][i-'a']; } } REP(i,1,q) { char op, c; int x; scanf(" %c%d", &op, &x); if (op=='+') { scanf(" %c", &c); a[x][++len[x]]=c; upd(x); } else --len[x]; puts(dp[len[1]][len[2]][len[3]]<=n?"YES":"NO"); } }