codeforces1303E. Erase Subsequences(dp)
题意:
给出两个字符串 s s s, p p p ,有一种操作:
取 s s s 中的某一个子序列 t t t ,将其加入到 p ′ p' p′的末尾 ,并在原串中删除。
最多只能进行两次操作,问 p ′ p' p′ 能否等于 p p p
题解:
枚举字符串 p p p 的断点,前一部分的长度为 l e n 1 len1 len1 ,后一部分的长度为 l e n 2 len2 len2 。
设 d p [ i ] [ j ] dp[i][j] dp[i][j] 表示原串 s s s 匹配前半部分的 i i i个字符,后半部分的 j j j 个字符,最少需要的长度。
那么只需判断 d p [ l e n 1 ] [ l e n 2 ] ≤ n dp[len1][len2] \leq n dp[len1][len2]≤n即可。
对于转移,有两个, d p [ i − 1 ] [ j ] , d p [ i ] [ j − 1 ] dp[i-1][j],dp[i][j-1] dp[i−1][j],dp[i][j−1] ,那么先预处理出每个后缀的每个字母最近的位置,然后看 p i / p j p_i/p_j pi/pj最近在哪即可。
代码:
#pragma GCC diagnostic error "-std=c++11"
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<queue>
#include<map>
#include<stack>
#include<set>
#include<ctime>
#define iss ios::sync_with_stdio(false)
using namespace std;
typedef unsigned long long ull;
typedef long long ll;
typedef pair<int,int> pii;
const int mod=1e9+7;
const int MAXN=5e2+5;
const int inf=0x3f3f3f3f;
int nex[MAXN][30];
char s[MAXN];
int dp[MAXN][MAXN];
char st[MAXN];
int main()
{
int t;
cin>>t;
while(t--)
{
cin >> s + 1;
cin >> st + 1;
int n = strlen(s + 1);
int m = strlen(st + 1);
for (int i = 1; i <= 26;i++)
nex[n+1][i] = n + 1;
for (int i = n; i >= 1;i--)
{
for (int j = 1; j <= 26;j++){
nex[i][j] = nex[i + 1][j];
}
nex[i][s[i] - 'a' + 1] = i;
}
//cout << nex[1][1] << endl;
int flag = 0;
for (int i = 0; i <= m;i++)
{
int len1 = i, len2 = m - i;
dp[0][0] = 0;
for (int j = 0; j <= len1;j++)
{
for (int k = 0; k <= len2;k++)
{
if(!j&&!k)
continue;
int pos1 = j, pos2 = i + k;
dp[j][k] = n + 1;
if(j-1>=0&&dp[j-1][k]<=n)
{
dp[j][k] = min(dp[j][k],nex[dp[j - 1][k] + 1][st[pos1] - 'a' + 1]);
}
if(k-1>=0&&dp[j][k-1]<=n)
{
dp[j][k] = min(dp[j][k], nex[dp[j][k-1] + 1][st[pos2] - 'a' + 1]);
}
}
}
if(dp[len1][len2]<=n) {
//cout << i << endl;
flag = 1;
break;
}
}
if(flag)
cout << "YES" << endl;
else
cout << "NO" << endl;
}
}

浙公网安备 33010602011771号