MENU

Solution. CF1336C Kaavi and Magic Spell

Description

给定一个字符串 $S$ 和一个字符串 $T$,每次操作可以删掉 $S$ 的第一个字符,然后放到一个初始为空的字符串 $A$ 的首部或尾部,你可以进行任意次操作,求有多少种不同的方法使得 $T$ 是 $A$ 的前缀。

$|T|\le|S|\le3000$

Solution

先考虑 $|S|=|T|$ 的情况。

设 $f_{i,j}$ 表示用 $S$ 的前 $j-i+1$ 位构造出 $T_{i\dots j}$ 的方案数。

不难得到转移方程:
$$
f_{i,j}=[S_{j-i+1}=T_i]f_{i+1,j}+[S_{j-i+1}=T_j]f_{i,j-1}
$$
初始化:
$$
f_{i,i}=[S_1=T_i]2
$$
区间 dp 即可。

如果 $|S|>|T|$,那么对于最后构造出来的 $A$,$(|T|,|A|]$ 这些位是什么我们并不关心,也就是说,我们实际上可以将 $T$ 的长度补至与 $S$ 等长,补充的这些位能够与任意字符匹配。

答案即为 $\sum_{i=|T|}^{|S|}f_{1,i}$。

Code

namespace Main{
    const int MOD = 998244353;
    const int L = 3005;
    int ls, lt, ans, f[L][L];
    char s[L], t[L];
    void Main(){
        scanf("%s%s", s + 1, t + 1);
        ls = strlen(s + 1), lt = strlen(t + 1);
        for(ri i = 1; i <= lt; i++) if(s[1] == t[i]) f[i][i] = 2;
        for(ri i = lt + 1; i <= ls; i++) f[i][i] = 2;
        for(ri len = 2; len <= ls; len++){
            for(ri i = 1; i + len - 1 <= ls; i++){
                ri j = i + len - 1;
                if(i > lt || s[len] == t[i]) f[i][j] += f[i+1][j];
                if(j > lt || s[len] == t[j]) f[i][j] += f[i][j-1];
                f[i][j] %= MOD;
            }
        }
        for(ri i = lt; i <= ls; i++) ans = (ans + f[1][i]) % MOD;
        write(ans);
        return;
    }
} // namespace
Last Modified: March 26, 2022
Archives Tip
QR Code for this page
Tipping QR Code