题目描述
题目解法
这道题一眼是个
d
p
dp
dp 题
看到数据范围
n
<
=
400
n<=400
n<=400,会有
2
2
2 个思路,要么是从前往后递推
d
p
dp
dp,要么是区间
d
p
dp
dp
我们发现这道题和区间
d
p
dp
dp 毫无关系,于是果断递推
d
p
dp
dp
我们把字符串
s
s
s 叫做操作串,字符串
t
t
t 叫做目标串
我们令
d
p
[
i
]
[
j
]
[
k
]
dp[i][j][k]
dp[i][j][k] 表示到操作串第
i
i
i 位,当前剩下的字符中前
j
j
j 个和后
k
k
k 个需在之后的操作中删掉
注意,一定是之后的操作中,之前的操作删去的字符默认已经删去了
显然,之后的操作一定不会删掉中间的点,而不删两边的点,所以这个
d
p
dp
dp 方程看似是正确的
考虑转移
令
d
i
g
dig
dig 为现在
R
R
R 串的长度
如果
s
i
=
0
或
1
s_i=0或1
si=0或1
d
p
[
i
]
[
j
]
[
k
]
+
=
d
p
[
i
−
1
]
[
j
]
[
k
−
1
]
(
k
>
=
1
)
dp[i][j][k]+=dp[i-1][j][k-1](k>=1)
dp[i][j][k]+=dp[i−1][j][k−1](k>=1) 即之后的操作需在后面删去
s
i
s_i
si
d
p
[
i
]
[
d
i
g
]
[
0
]
+
=
d
p
[
i
−
1
]
[
d
i
g
−
1
]
[
0
]
dp[i][dig][0]+=dp[i-1][dig-1][0]
dp[i][dig][0]+=dp[i−1][dig−1][0] 即之后的操作需在前面删去
s
i
s_i
si
d
p
[
i
]
[
j
]
[
0
]
+
=
d
p
[
i
−
1
]
[
j
]
[
0
]
dp[i][j][0]+=dp[i-1][j][0]
dp[i][j][0]+=dp[i−1][j][0] 即在后面加入
s
i
s_i
si
注意从前面删和从后面删不一样
如果
s
i
=
′
−
′
s_i ='-'
si=′−′
d
p
[
i
]
[
j
]
[
k
]
+
=
d
p
[
i
−
1
]
[
j
+
1
]
[
k
]
+
d
p
[
i
−
1
]
[
j
]
[
k
+
1
]
dp[i][j][k]+=dp[i-1][j+1][k]+dp[i-1][j][k+1]
dp[i][j][k]+=dp[i−1][j+1][k]+dp[i−1][j][k+1],这没什么好解释的
最后的答案就是 d p [ n ] [ 0 ] [ 0 ] dp[n][0][0] dp[n][0][0]
这里需要特判一下最后 R R R 串的长度是否等于目标串的长度,不等于答案为 0 0 0,不然民间数据会 W A 20 p t s WA20pts WA20pts
#include <bits/stdc++.h>
using namespace std;
const int N(410),P(1e9+7);
int n,m,dp[N][N][N];
char s[N],t[N];
inline int read(){
int FF=0,RR=1;
char ch=getchar();
for(;!isdigit(ch);ch=getchar()) if(ch=='-') RR=-1;
for(;isdigit(ch);ch=getchar()) FF=(FF<<1)+(FF<<3)+ch-48;
return FF*RR;
}
void work(){
memset(dp,0,sizeof(dp));
n=read(),m=read();
scanf("%s%s",s+1,t+1);
dp[0][0][0]=1;
int dig=0;
for(int i=1;i<=n;i++){
if(s[i]=='0'||s[i]=='1'){
dig++;
//在右边删掉
for(int j=0;j<=dig;j++)
for(int k=1;k<=dig;k++)
dp[i][j][k]=(dp[i][j][k]+dp[i-1][j][k-1])%P;
//在左边删掉
dp[i][dig][0]=(dp[i][dig][0]+dp[i-1][dig-1][0])%P;
//不删
for(int j=0;j<dig;j++)
if(dig-j<=m&&s[i]==t[dig-j])
dp[i][j][0]=(dp[i][j][0]+dp[i-1][j][0])%P;
}
else{
dig--;
for(int j=0;j<=dig;j++)
for(int k=0;k<=dig;k++)
dp[i][j][k]=((dp[i][j][k]+dp[i-1][j+1][k])%P+dp[i-1][j][k+1])%P;
}
}
if(dig!=m) puts("0");
else printf("%d\n",dp[n][0][0]);
}
int main(){
int T=read();
while(T--) work();
return 0;
}