题目:http://codeforces.com/contest/1303/problem/E
题意:给定字符串
s
s
s和
t
t
t,将
s
s
s抽取出一个子串(可以不连续),得到串
p
1
p_1
p1,再将剩下的字符串
s
2
s_2
s2抽取一个子串
p
2
p_2
p2(可以为空),
p
1
p_1
p1和
p
2
p_2
p2连接,问能否得到字符串t。说白了就是能否从s种找到两个不重叠的子串
p
1
p_1
p1和
p
2
p_2
p2,使得
p
1
+
p
2
=
t
p_1+p_2=t
p1+p2=t其中
1
<
=
l
e
n
g
t
h
(
s
)
,
l
e
n
g
t
h
(
t
)
<
=
400
1<=length(s),length(t)<=400
1<=length(s),length(t)<=400
参考:http://codeforces.com/blog/entry/73872
参考2:https://www.bilibili.com/video/av88620060?p=5
题解:将字符串
t
t
t拆分为
t
1
+
t
2
t1+t2
t1+t2定义
d
p
[
i
]
[
j
]
dp[i][j]
dp[i][j]表示凑成
t
1
t1
t1的前
i
i
i个和
t
2
t2
t2的前
j
j
j个需要的
s
s
s的最小长度。
d
p
[
i
]
[
j
]
dp[i][j]
dp[i][j]由
d
p
[
i
−
1
]
[
j
]
dp[i-1][j]
dp[i−1][j]和
d
p
[
i
]
[
j
−
1
]
dp[i][j-1]
dp[i][j−1]转移,每次寻找下一个和
t
1
[
i
]
/
t
2
[
j
]
t1[i]/t2[j]
t1[i]/t2[j]匹配的最小的s的位置,需要预处理s的每一个字符的最小位置
n
x
t
[
]
[
26
]
nxt[][26]
nxt[][26]
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int maxn = 410;
string s,t;
int n,m;
int nxt[maxn][30];
int dp[maxn][maxn];
void nxt_init() {
for(int i = 0;i <= 25;i++) nxt[n][i] = n+1;
for(int i = n;i >= 1;i--) {
for(int j = 0;j <= 25;j++)
nxt[i-1][j] = nxt[i][j];
nxt[i-1][s[i-1]-'a'] = i;
}
}
bool judge(string t1,string t2) {
int len1 = t1.length(),len2 = t2.length();
dp[0][0] = 0;
for(int i = 0;i <= len1;i++) {
for(int j = 0;j <= len2;j++) {
if(!i && !j) continue;
dp[i][j] = n+1;
if(i && dp[i-1][j] < n) dp[i][j] = min(dp[i][j],nxt[dp[i-1][j]][t1[i-1]-'a']);
if(j && dp[i][j-1] < n) dp[i][j] = min(dp[i][j],nxt[dp[i][j-1]][t2[j-1]-'a']);
}
}
return dp[len1][len2]<=n;
}
int main() {
int T;cin>>T;
while(T--) {
cin>>s>>t;
bool flag = 0;
m = t.length();
n = s.length();
nxt_init();
for(int i = 0;i < m;i++) {
if(judge(t.substr(0,i),t.substr(i))) {
flag = 1;break;
}
}
if(flag) puts("YES");
else puts("NO");
}
}
除了上述做法,网上也看到了另一种dp方法,不需要借用额外空间。
定义
d
p
[
i
]
[
j
]
dp[i][j]
dp[i][j]表示用了s的前i个和t1的前j个能得到的最大的t2的长度。转移时拿
s
[
i
−
1
]
s[i-1]
s[i−1]和
t
1
[
j
−
1
]
t1[j-1]
t1[j−1]、
t
2
[
d
p
[
i
−
1
]
[
j
]
]
t2[dp[i-1][j]]
t2[dp[i−1][j]]比较。
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int maxn = 410;
string s,t;
int n,m;
int dp[maxn][maxn];
bool judge(string t1,string t2) {
int len1 = t1.length(),len2 = t2.length();
memset(dp,-1,sizeof(dp));
dp[0][0] = 0;
for(int i = 0;i <= n;i++) {
for(int j = 0;j <= len1;j++) {
if(i) dp[i][j] = max(dp[i-1][j],dp[i][j]);
if(i && j && dp[i-1][j-1] != -1 && s[i-1] == t1[j-1])
dp[i][j] = max(dp[i-1][j-1],dp[i][j]);
if(i && dp[i-1][j] != -1 && t2[dp[i-1][j]] == s[i-1])
dp[i][j] = max(dp[i][j],dp[i-1][j]+1);
}
}
return dp[n][len1]>=len2;
}
int main() {
int T;cin>>T;
while(T--) {
cin>>s>>t;
bool flag = 0;
m = t.length();
n = s.length();
for(int i = 0;i < m;i++) {
if(judge(t.substr(0,i),t.substr(i))) {
flag = 1;break;
}
}
if(flag) puts("YES");
else puts("NO");
}
}