题目
一个长为n(n<=1e5)的串,q(q<=1000)次操作,
每次操作对第type(type={1,2,3})个串里添加一个字符,或删去一个字符
保证每个type串长不超过250,
问每次操作后,三个串是否能同时构成原串的子序列,且三段序列不相交
思路来源
https://www.cnblogs.com/npugen/p/10798295.html
题解
感觉是dp,然而就是不会dp,250*250*250的空间大概2e7,也是没想到吧...
先预处理Next数组,Next[i][j]表示[i,n]中第一次出现j的位置的最小下标
这个开一个dp数组倒着处理,
如果当前第i位字母是β,更新Next[i][β],其余的字母沿用i+1的结果
然后开一个dp[i][j][k]的数组,
dp[i][j][k]代表第一个串长为i,第二个串长为j,第三个串长为k时所需的原串的最小串长
实际操作时,维护的值是所需的原串的最小下标,也就是串长减一,原理是一样的
这才有了串长为0时,下标为-1的dp[0][0][0]=-1的操作
每次更新操作时,只需更新包含更新点所在的平面片,复杂度O(q*250*250)
将dp[i][j][k]想象成三维(i,j,k)的点,模拟一下更新过程即可
删除时无需更新,下次更新时那个平面片会利用之前没被删除的结果对原来的覆盖
每次询问,只需看串长≤n也就是下标<n即可
代码
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
const int maxn=1e5+10;
const int maxm=255;
int n,q;
//dp[i][j][k]代表第一个串长为i,第二个串长为j,第三个串长为k时所需的原串的最小串长
int dp[maxm][maxm][maxm];
int Next[maxn][26];//Next[i][j]表示[i,n]中第一次出现j的位置的最小下标
int type;
char s[maxn];
char op[3],ch[3];
string now[3];//现在每个字符串的字符
int miin[3],maax[3];
//更新下界 更新上界
//将dp[i][j][k]考虑成一个三维立体结构,则每一个值的加入只需更新一个二维平面片
void init(char s[],int n)
{
for(int j=0;j<26;++j)//由于串长的最大下标为n-1
Next[n][j]=Next[n+1][j]=n;//此处令最小下标为n,即INF
for(int i=n-1;i>=0;--i)
{
int num=s[i]-'a';
for(int j=0;j<26;++j)
{
if(j==num)Next[i][j]=i;//新开一个
else Next[i][j]=Next[i+1][j];//沿用上一个
}
}
}
void cal(int i,int j,int k)
{
int &ans=dp[i][j][k];
ans=n;//先赋dp[i][j][k]=INF即n
//以dp[i][j][k]=min(dp[i][j][k],Next[dp[i-1][j][k]+1][now[0][i-1]-'a']为例
//说明是上一个状态的最小下标往后的下标p里[p,n]里最早出现当前字母的位置的一个
if(i)ans=min(ans,Next[dp[i-1][j][k]+1][now[0][i-1]-'a']);
if(j)ans=min(ans,Next[dp[i][j-1][k]+1][now[1][j-1]-'a']);
if(k)ans=min(ans,Next[dp[i][j][k-1]+1][now[2][k-1]-'a']);
}
int main()
{
scanf("%d%d",&n,&q);
scanf("%s",s);
init(s,n);
dp[0][0][0]=-1;//串长为0,则最小下标为-1 下标=串长-1
for(int i=1;i<=q;++i)
{
scanf("%s%d",op,&type);
type--;
if(op[0]=='+')
{
scanf("%s",ch);
now[type]+=ch[0];
for(int j=0;j<3;++j)
{
miin[j]=0;
maax[j]=now[j].size();
}
miin[type]=maax[type];//要更新的值 只需更新一维
for(int a=miin[0];a<=maax[0];++a)
{
for(int b=miin[1];b<=maax[1];++b)
{
for(int c=miin[2];c<=maax[2];++c)
{
cal(a,b,c);
}
}
}
}
else now[type].pop_back();
puts(dp[now[0].size()][now[1].size()][now[2].size()]<n?"YES":"NO");
}
return 0;
}