『妙不可言系列2』CF1336C Kaavi and Magic Spell

P r o b l e m \mathrm{Problem} Problem

Kaavi, the mysterious fortune teller, deeply believes that one's fate is inevitable and unavoidable. Of course, she makes her living by predicting others' future. While doing divination, Kaavi believes that magic spells can provide great power for her to see the future.

Kaavi has a string $ T $ of length $ m $ and all the strings with the prefix $ T $ are magic spells. Kaavi also has a string $ S $ of length $ n $ and an empty string $ A $ .

During the divination, Kaavi needs to perform a sequence of operations. There are two different operations:

  • Delete the first character of S S S and add it at the front of A A A .
  • Delete the first character of S S S and add it at the back of A A A .

Kaavi can perform no more than n n n operations. To finish the divination, she wants to know the number of different operation sequences to make A A A a magic spell (i.e. with the prefix T T T ). As her assistant, can you help her? The answer might be huge, so Kaavi only needs to know the answer modulo 998   244   353 998\,244\,353 998244353 .

Two operation sequences are considered different if they are different in length or there exists an i i i that their i i i -th operation is different.

A substring is a contiguous sequence of characters within a string. A prefix of a string S S S is a substring of S S S that occurs at the beginning of S S S .

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

S o l u t i o n \mathrm{Solution} Solution

这道题的特性在于,A串的特性是两边拓展的。我们可以从A串这个与众不同的特点来思考问题。

  • 对于不断两边拓展的问题需要想到区间DP

这一点是解题的关键。但是这道题要求这个串满足T是该串的前缀,那我们可以在状态上做手脚。

  • f [ l ] [ r ] f[l][r] f[l][r]表示用 ( r − l + 1 ) (r-l+1) (rl+1)个S字符前后拼接形成A串,A串的区间 [ L , R ] [\mathrm L,\text R] [L,R]内的任意一个字符符合条件的方案数。这里字符i符合条件当且仅当满足 i > ∣ T ∣ i>|T| i>T或者 i ≤ ∣ T ∣ 且 A i = T i i\le |T|且A_i=T_i iTAi=Ti.

那样我们就可以考虑使用区间DP的方式去进去转移了。

我们考虑方程的转移,对于一个 l l l r r r和区间的长度 len=r-l+1 . \text{len=r-l+1}. len=r-l+1.

  • 对于s[len]=t[i]或者i>m的情况,说明当前新加入的字母足以匹配可以成为开头或开头可以选择任意字母,那么就有: f [ i ] [ j ] + = f [ i + 1 ] [ j ] f[i][j]+=f[i+1][j] f[i][j]+=f[i+1][j]
  • 对于s[len]=t[j]或者j>m的情况,同理: f [ i ] [ j ] + = f [ i ] [ j − 1 ] f[i][j]+=f[i][j-1] f[i][j]+=f[i][j1]

C o d e \mathrm{Code} Code

#include <bits/stdc++.h>

using namespace std;
const int N = 4000;
const int P = 998244353;

int n, m;
int f[N][N];
char S[N], T[N];

int main(void)
{
	cin >> S+1 >> T+1;
	n = strlen(S+1);
	m = strlen(T+1);
	for (int i=1;i<=n;++i)
		f[i][i] = (i > m || S[1] == T[i])*2;
	for (int len=2;len<=n;++len)
		for (int i=1;i+len-1<=n;++i) {
			int j = i + len - 1;
			if (S[len] == T[i] || i > m) f[i][j] = (f[i][j] + f[i+1][j]) % P;
			if (S[len] == T[j] || j > m) f[i][j] = (f[i][j] + f[i][j-1]) % P;
		} 	
	int res = 0;
	for (int i=m;i<=n;++i)
		res = (res + f[1][i]) % P;
	cout << res << endl;
	return 0;
} 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值