Codeforces Round #635 (Div. 2) 比赛人数14830
[codeforces 1337E] Kaavi and Magic Spell 区间动归dp
总目录详见https://blog.csdn.net/mrcrack/article/details/103564004
在线测评地址https://codeforces.com/contest/1337/problem/E
Problem | Lang | Verdict | Time | Memory |
---|---|---|---|---|
E - Kaavi and Magic Spell | GNU C++17 | Accepted | 109 ms | 70900 KB |
摘自https://blog.csdn.net/qq_43676357/article/details/105559491?fps=1&locationNum=2
我看了网上的一些博客和题解 在这里谈谈我对这道题的看法
题意很好理解 经过合法操作以后找出前缀为t的序列的个数
我们这里可以形象的理解 把字符串t补齐 和N一样大
(斗地主中的癞子玩过吧) 我们定义’*'为万能字符
那么题意就变为经过合法操作以后 可以变成t字符串的个数
比如样例1
s = “abab”
t = “ba**”
开始题解
首先定义dp[l][r]为匹配到t字符串区间为l, r的个数
那么答案很明显就是从M到N的dp[1][i]的个数//因为M-N区间的万能字符 我们只需要前缀 所以这些都是可行字符
状态转移分四种情况 既然是可以往左和往右加 那么肯定就是对dp[l][r]找dp[l + 1][r] 和 dp[l][r -1]的关系 分别对应次字符往左还是往右放
我们用i来枚举每次操作(从s中从前往后一直拿字符嘛)
因为你拿了多少字符 肯定也就确定了l 和 r 的差值 (你全部都得放进去) 所以分别枚举l的所有长度r别越界
case1 (s[i] == t[l])
此时我们可以把这个字符放到左边 所以dp[l][r] += dp[l + 1][r] % mod;
case2 (s[i] == t[r])
此时我们可以吧这个字符放到右边 所以dp[l][r] += dp[l][r - 1] % mod;
还有两个 万能字符
case3 (l > M)
这个时候我们可以让他去匹配我们的万能字符呀 因为l > M 这些字符可以全部转移到万能字符上面去 所以这些字符是什么其实已经不重要了 匹配够长度就可以了dp[l][r] += dp[l + 1][r] % mod;
case4 (r > M)
和上面一样 理解一下 放右边就可以了
dp[l][r] += dp[l][r - 1] % mod;
关于下面的初始化,虽然有些神奇,但在编码的过程中,确容易理解,因若不这样设置,得不到想要的数据。
dp[i][i-1]=1是为dp[l][r]=(dp[l][r]+dp[l+1][r])%mod而初始化
dp[i+1][i]=1是为dp[l][r]=(dp[l][r]+dp[l+1][r])%mod而初始化
若有不明,请看如下样例模拟
abab
ba
12
S abab
T ba**
T位置 1 2 3 4
T字串 b a * *
读入S字串的第一个字符a
位置1 2 3 4
(1)摆放a 对dp[1][1]的贡献是0
(2)摆放 a 对dp[2][2]的贡献是1
(3)摆放 a 对dp[3][3]的贡献是1
(4)摆放 a 对dp[4][4]的贡献是1
读入S字串的第二个字符b
位置1 2 3 4
(1)摆放a b 对dp[1][2]的贡献是0
(2)摆放b a 对dp[1][2]的贡献是1
(2)摆放 a b 对dp[2][3]的贡献是1
(3)摆放 b a 对dp[3][3]的贡献是0
(3)摆放 a b 对dp[3][3]的贡献是1
(4)摆放 b a 对dp[4][4]的贡献是1
读入S字串的第三个字符a
位置1 2 3 4
(1)摆放a b a 对dp[1][3]的贡献是0
(2)摆放b a a 对dp[1][3]的贡献是1
(2)摆放a a b 对dp[1][3]的贡献是0
(2)摆放 a b a 对dp[2][4]的贡献是1
(3)摆放a b a 对dp[1][3]的贡献是0
(3)摆放 b a a 对dp[2][4]的贡献是0
(3)摆放 a a b 对dp[2][4]的贡献是1
(4)摆放 a b a 对dp[2][4]的贡献是1
读入S字串的第四个字符a
位置1 2 3 4
(1)摆放a b a b 对dp[1][4]的贡献是0
(2)摆放b a a b 对dp[1][4]的贡献是1
(2)摆放a a b b 对dp[1][4]的贡献是0
(2)摆放b a b a 对dp[1][4]的贡献是1
(3)摆放a b a b 对dp[1][4]的贡献是0
(3)摆放b b a a 对dp[1][4]的贡献是0
(3)摆放b a a b 对dp[1][4]的贡献是1
(4)摆放b a b a 对dp[1][4]的贡献是1
AC代码如下
#include <stdio.h>
#include <string.h>
#define maxn 3010
#define mod 998244353
#define LL long long
char s[maxn],t[maxn];
LL dp[maxn][maxn],sum;
int main(){
int n,m,i,len,l,r;
scanf("%s%s",s+1,t+1);
n=strlen(s+1),m=strlen(t+1);
for(i=1;i<=n;i++)dp[i][i-1]=1,dp[i+1][i]=1;//神奇的初始化,为了后面数据处理而服务
for(i=1;len=i,i<=n;i++)
for(l=1;r=l+len-1,r<=n;l++){
if(l>m||s[i]==t[l])dp[l][r]=(dp[l][r]+dp[l+1][r])%mod;
if(r>m||s[i]==t[r])dp[l][r]=(dp[l][r]+dp[l][r-1])%mod;
}
for(i=m;i<=n;i++)sum=(sum+dp[1][i])%mod;
printf("%lld\n",sum);
return 0;
}