题意
给出一个字符串 T T T,和字符串 S S S,一次操作可以从 S S S的开头取出一个字符,加入新字符串 A A A的开头或者结尾,问有多少种操作的组合,可以使得 T T T是 A A A的前缀。
思路
考虑
d
p
dp
dp,设
f
(
i
,
j
)
f(i,j)
f(i,j)表示使用
S
S
S中前
i
i
i个字符,第
1
1
1个字符与
T
T
T的第
j
j
j个对齐,有多少种方法。
如果要把第
i
i
i个加入开头,有
f
(
i
,
j
)
+
=
f
(
i
−
1
,
j
+
1
)
[
S
[
i
]
=
=
T
[
j
]
]
f(i,j) += f(i-1,j+1) [S[i]==T[j]]
f(i,j)+=f(i−1,j+1)[S[i]==T[j]]
如果要放到结尾,如果此时前
i
i
i个还没有超出后
m
−
j
+
1
m-j+1
m−j+1个的长度,有
f
(
i
,
j
)
=
f
(
i
,
j
−
1
)
[
i
≤
m
−
j
+
1
且
S
[
i
]
=
=
T
[
j
+
i
−
1
]
]
f(i,j) = f(i,j-1) [i \leq m-j+1 且 S[i] == T[j+i-1]]
f(i,j)=f(i,j−1)[i≤m−j+1且S[i]==T[j+i−1]]
否则可以直接放到结尾
f
(
i
,
j
)
=
f
(
i
,
j
−
1
)
[
i
>
m
−
j
+
1
]
f(i,j) = f(i,j-1)[i \gt m-j+1]
f(i,j)=f(i,j−1)[i>m−j+1]
注意点
初始化要将 f ( 0 , 1 ) f(0,1) f(0,1)到 f ( 0 , n + 1 ) f(0,n+1) f(0,n+1)设为 1 1 1,因为 f ( 1 , n ) f(1,n) f(1,n)转移时会用到 f ( 0 , n + 1 ) f(0,n+1) f(0,n+1)
代码
#include<bits/stdc++.h>
#define ll long long
#define N 3005
#define mod 998244353
#define rep(i,a,n) for (int i=a;i<=n;i++)
#define per(i,a,n) for (int i=n;i>=a;i--)
#define inf 0x3f3f3f3f
#define pb push_back
#define mp make_pair
#define lowbit(i) ((i)&(-i))
#define VI vector<int>
using namespace std;
char s[N],t[N];
int n,m,f[N][N];
int main(){
//freopen(".in","r",stdin);
//freopen(".out","w",stdout);
scanf("%s%s",s+1,t+1);
n = strlen(s+1);m = strlen(t+1);
rep(j,1,n+1) f[0][j] = 1;
rep(i,1,n){
rep(j,1,n){
if(j>m||s[i]==t[j]) f[i][j] = (f[i][j]+f[i-1][j+1])%mod;
if(i <= m-j+1){
if(s[i]==t[j+i-1]) f[i][j] = (f[i][j]+f[i-1][j])%mod;
}else{
f[i][j] = (f[i][j]+f[i-1][j])%mod;
}
//cout << i << ' ' << j << ' ' << f[i][j] << endl;
}
}
int ans = 0;
rep(i,m,n){
ans = (ans+f[i][1])%mod;
}
cout << ans << endl;
return 0;
}