题目大意:

已知有字符串s,t。每次我们可以从左开始,选择s的字符,选择好的字符可以放在a的左边或者右边(a原始为空)。现在问我们,有多少种不同的放法可以使得a的前缀是t.

s,t长度为n, n<=1e3.

解题思路:

这里我们考虑使用区间DP,设dp[l][r] 为a成功匹配t时候,[l,r]满足要求的串的个数(满足要求指:前缀是t,后面是任意字符的情况)。那么我们可以模拟这个过程,从左开始选择s的字符,然后已经选了的s的长度作为滑窗的长度(就是我们选择了第i个字符,那么构造一个长度为i的滑窗),开始从左到右滑求这一段是否能由上一个子情况转移(为什么用滑窗来考虑呢?其实我们思考一下,在s中选取前n个字符,那么这n个字符肯定是连在一起的吧,同时这n个字符最后肯定是出现在匹配结果的任意一个滑窗位置)每次我们可以选择将这个字符放在[l-1,r]处,或者[l,r-1]处。假如选择的字符恰好落在了匹配的范围内且和匹配的字符相同(即t的范围),或者落在了匹配范围外,那么

dp[l][r] += dp[l+1][r]或者dp[l][r] += dp[l][r-1].

 注意初始情况,选择s的第一个字符的时候,由于第一次操作我们可以push front或者push back所以最小的情况为2,不理解的话看看cf的第一个样例为什么是12不是6.

#include <bits/stdc++.h>
#define OPEN 0
#define int long long
using namespace std;
const int MAXN = 3010;
const int MODN = 998244353;
char s[MAXN], t[MAXN];
int32_t main() {
#if OPEN
freopen("vsin.txt", "r", stdin);
#endif
scanf("%s %s", s + 1, t + 1);
int n = strlen(s + 1);
int m = strlen(t + 1);
vector<vector<int>> dp(MAXN, vector<int>(MAXN, 0));
for (int len = 1; len <= n; len++)
for (int l = 1; l + len - 1 <= n; l++) {
int r = l + len - 1;
if (len == 1) {

if (l>m || s[len] == t[l])dp[l][r] = 2;
//cerr << l << " " << r << " " << dp[l][r] << endl;
continue;
}
if (l>m || s[len] == t[l])dp[l][r] += dp[l + 1][r], dp[l][r] %= MODN;
if (r>m || s[len] == t[r])dp[l][r] += dp[l][r - 1], dp[l][r] %= MODN;
}
int sum = 0;
for (int i = m; i <= n; i++)sum += dp[1][i], sum %= MODN;
cout << sum << endl;
return 0;
}