题目链接:http://codeforces.com/contest/1303/problem/E
题目大意:
给你一个字符串S和一个字符串T。问能不能在S中找到一个子序列S1,然后从S中删除S1.再去删除后的字符串T中再找一个子序列S2。然后用S1+S2拼接成T。
思路:我们枚举T的分割点。进行dp。dp[i][j]:表示前i个字符和t1匹配到第j个字符时。能和t2匹配的最大长度。如果dp[|s|][|t1|]==|t2|就可行。注意t1和t2可能一个为空。特判就可以了。
#include <bits/stdc++.h>
#define LL long long
using namespace std;
int dp[500][500];
int check(char s[], char t1[], char t2[]){
memset(dp, -1, sizeof(dp));
int n=strlen(s+1), n1=strlen(t1+1), n2=strlen(t2+1);
dp[0][0]=0;
for(int i=1; i<=n; i++){
dp[i][0]=0;
for(int j=0; j<=n1; j++){
if(s[i]==t1[j]){
dp[i][j]=max(dp[i][j], dp[i-1][j-1]);//t1匹配数+1,但是t2的匹配数没有变化
}
if(dp[i-1][j]<n2&&s[i]==t2[dp[i-1][j]+1]){//t2匹配数+1,t1的匹配数没有变化
dp[i][j]=max(dp[i][j], dp[i-1][j]+1);
}
dp[i][j]=max(dp[i][j], dp[i-1][j]);//前缀和最大值
}
}
int ans=dp[n][n1];
if(ans==n2){
return 1;
}
else{
return 0;
}
}
int main()
{
int T;
scanf("%d", &T);
while(T--){
char s[500]={0}, t[500]={0}, t1[500]={0}, t2[500]={0};
scanf("%s%s", s+1, t+1);
int n=strlen(t+1), f=0;
int tot=1;
for(int i=1; i<=strlen(s+1); i++){//t1, t2为空特判
if(s[i]==t[tot]){
tot++;
}
if(tot==n+1){
f=1;
break;
}
}
if(f){
printf("YES\n");
continue;
}
for(int len=1; len<=n-1; len++){
for(int i=1; i<=len; i++){
t1[i]=t[i];
}
for(int i=len+1; i<=n; i++){
t2[i-len]=t[i];
}
t1[len+1]=t2[n-len+1]=0;
if(check(s, t1, t2)){
printf("YES\n");
f=1;
break;
}
}
if(f==0){
printf("NO\n");
}
}
return 0;
}