Codeforces Round #635 (Div. 2) E - Kaavi and Magic Spell 区间DP 巧妙转化

考虑dp[i][j]:T串 i-j 区间匹配,的方案数。

由于序列是不断增长,最终序列只要前缀包含T即可,所以我们把T串变成T***(后面加*知道与S串相同长度)
那结果就是 \sum_{i=m}^n dp[1][i].

我们枚举S串,一位一位更新区间DP。

由于每一位S会让目标串长度加一,所以枚举的Si,中的i就是区间DP的长度。

所以二维区间DP就可以维护更新了。

考虑更新:

我们知道S串1   -   i-1,构成T串的所有方案。

只需要看S[i]与T[l],t[r]的关系即可。

如果S[i]等于T[l]表示,S[i]可以加在  T[l+1,r]前面,构成T[l,r].

同理如果S[i]等于T[r]表示,S[i]可以加在T[l,r-1]后面,构成T[l,r]

T[m+1,n]中间的字符是任意字符,即任何S都能匹配。(相当于先放后面再放前面)

比如样例1:

S:abab

T:ba**

S的第一个字符可以组成:T[2,2],T[3,3],T[4,4]

S的前两个个字符组成:T[1,2],T[2,3],T[3,4]

 ……

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define ls (o<<1)
#define rs (o<<1|1)
#define pb push_back
const double PI= acos(-1.0);
const int M = 3e3+7;
/*
int head[M],cnt;
void init(){cnt=0,memset(head,-1,sizeof(head));}
struct EDGE{int to,nxt,val;}ee[M*2];
void add(int x,int y){ee[++cnt].nxt=head[x],ee[cnt].to=y,head[x]=cnt;}
*/
const int mod= 998244353;
ll dp[M][M];
char s[M],t[M];
int main()
{
	ios::sync_with_stdio(false);
  	cin.tie(0);
  	cin>>(s+1)>>(t+1);
  	int n=strlen(s+1),m=strlen(t+1);
  	for(int i=1;i<=n+1;i++)dp[i][i-1]=1;
  	ll ans=0;
  	/*
	S:abab
	T:ba**
	  */
  	for(int i=1;i<=n;i++)//枚举S 
  	{
  		for(int l=1;l+i-1<=n;l++)
  		{
  			int r=l+i-1;
  			if(s[i]==t[l]||l>m)dp[l][r]+=dp[l+1][r];
  			if(s[i]==t[r]||r>m)dp[l][r]+=dp[l][r-1];
  			dp[l][r]%=mod;
		}
	}
	for(int i=m;i<=n;i++)ans+=dp[1][i],ans%=mod;
	cout<<ans<<endl;
	return 0;
}

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值