题目链接:
https://codeforces.ml/problemset/problem/1303/E
解题思路:
参考大佬的视频:https://www.bilibili.com/video/BV1H74113746 from=search&seid=5562208735290586020
自我吐槽:这都能dp…
将
t
t
t字符串分成前后两个字符串
t
1
t1
t1,
t
2
t2
t2字符串,接下来设置dp状态,
d
p
[
l
e
n
s
]
[
l
e
n
t
1
]
[
l
e
n
t
2
]
=
1
dp[lens][lent1][lent2]=1
dp[lens][lent1][lent2]=1,就代表s字符串的前
l
e
n
s
lens
lens的长度存在两个不重叠的子序列
很显然当
d
p
[
l
e
n
s
]
[
l
e
n
t
1
]
[
l
e
n
t
2
]
=
1
dp[lens][lent1][lent2]=1
dp[lens][lent1][lent2]=1,
d
p
[
l
e
n
s
+
1
]
[
l
e
n
1
]
[
l
e
n
2
]
=
1
dp[lens+1][len1][len2]=1
dp[lens+1][len1][len2]=1
如果
s
[
l
e
n
s
]
=
=
t
1
[
l
e
n
t
1
]
s[lens]==t1[lent1]
s[lens]==t1[lent1]
那么
d
p
[
l
e
n
s
+
1
]
[
l
e
n
t
1
+
1
]
[
l
e
n
2
]
=
m
a
x
(
d
p
[
l
e
n
s
+
1
]
[
l
e
n
t
1
+
1
]
[
l
e
n
2
]
,
d
p
[
l
e
n
s
]
[
l
e
n
1
]
[
l
e
n
2
]
)
dp[lens+1][lent1+1][len2]=max(dp[lens+1][lent1+1][len2],dp[lens][len1][len2])
dp[lens+1][lent1+1][len2]=max(dp[lens+1][lent1+1][len2],dp[lens][len1][len2])
如果
s
[
l
e
n
s
]
=
=
t
2
[
l
e
n
t
2
]
s[lens]==t2[lent2]
s[lens]==t2[lent2]
那么
d
p
[
l
e
n
s
+
1
]
[
l
e
n
t
1
]
[
l
e
n
t
2
+
1
]
=
m
a
x
(
d
p
[
l
e
n
s
+
1
]
[
l
e
n
t
1
]
[
l
e
n
t
2
+
1
]
,
d
p
[
l
e
n
s
]
[
l
e
n
1
]
[
l
e
n
2
]
)
dp[lens+1][lent1][lent2+1]=max(dp[lens+1][lent1][lent2+1],dp[lens][len1][len2])
dp[lens+1][lent1][lent2+1]=max(dp[lens+1][lent1][lent2+1],dp[lens][len1][len2])
最后:
d
p
[
l
e
n
s
+
1
]
[
l
e
n
1
]
[
l
e
n
2
]
=
m
a
x
(
d
p
[
l
e
n
s
+
1
]
[
l
e
n
1
]
[
l
e
n
2
]
,
d
p
[
l
e
n
s
]
[
l
e
n
1
]
[
l
e
n
2
]
)
dp[lens+1][len1][len2]=max(dp[lens+1][len1][len2],dp[lens][len1][len2])
dp[lens+1][len1][len2]=max(dp[lens+1][len1][len2],dp[lens][len1][len2])
这个理论上可解,但是时间不允许,加上划分
t
1
,
t
2
t1,t2
t1,t2字符串需要
O
(
n
)
O(n)
O(n)时间,总复杂度为
O
(
n
4
)
O(n^4)
O(n4)
重点来了!!!
对于状态只有01的dp往往可以压缩一维!!!
选择将最后一维压缩到状态中,那么
d
p
[
i
]
[
j
]
dp[i][j]
dp[i][j]就代表
s
s
s中匹配到
i
i
i,
t
1
t1
t1中匹配到
j
j
j的
t
2
t2
t2中最大的匹配位置
AC代码:
#include<bits/stdc++.h>
using namespace std;
int T;
int dp[410][410];
bool check(string s,string t) {
int ls=s.size(),lt=t.size(),idx=0;
for(int i=0; i<ls; i++)
if(s[i]==t[idx]) idx++;
if(idx==lt) return true;
else return false;
}
bool check(string s,string t1,string t2) {
//cout<<t1<<" "<<t2<<endl;
memset(dp,-1,sizeof(dp));//初始化为-1
dp[0][0]=0;
int ls=s.size(),lt1=t1.size(),lt2=t2.size();
for(int i=0; i<ls; i++)
for(int j=0; j<=lt1; j++)
if(dp[i][j]>=0) {//代表该状态能否推导下一状态
if(j<lt1&&t1[j]==s[i])
dp[i+1][j+1]=max(dp[i+1][j+1],dp[i][j]);
//因为匹配的是t1字符串,所以不用dp值加一
if(dp[i][j]<lt2&&t2[dp[i][j]]==s[i])
dp[i+1][j]=max(dp[i+1][j],dp[i][j]+1);
//匹配t2字符串,符合条件的话,dp[i][j]值加一
dp[i+1][j]=max(dp[i+1][j],dp[i][j]);
//当前第i个字符都不匹配
}
if(dp[ls][lt1]>=lt2) return true;//如果最后的dp值大于等于lt2即可
else return false;
}
void solve() {
string s,t;
cin>>s>>t;
if(check(s,t)) {//先判断t是不是s的子序列再划分
printf("YES\n");
return;
}
int lt=t.size();
for(int i=0; i<lt-1; i++) {
string t1="",t2="";
for(int j=0; j<=i; j++) t1+=t[j];
for(int j=i+1; j<lt; j++) t2+=t[j];
if(check(s,t1,t2)) {
printf("YES\n");
return;
}
}
printf("NO\n");
return;
}
int main() {
cin>>T;
while(T--) solve();
}