codeforces 1336C - Kaavi and Magic Spell(思维,区间DP)

题目大意:

已知有字符串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;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值