C. Kaavi and Magic Spell(Codeforces Round #635)

Link

题意

给出一个字符串 T T T,和字符串 S S S,一次操作可以从 S S S的开头取出一个字符,加入新字符串 A A A的开头或者结尾,问有多少种操作的组合,可以使得 T T T A A A的前缀。

思路

考虑 d p dp dp,设 f ( i , j ) f(i,j) f(i,j)表示使用 S S S中前 i i i个字符,第 1 1 1个字符与 T T T的第 j j j个对齐,有多少种方法。
如果要把第 i i i个加入开头,有
f ( i , j ) + = f ( i − 1 , j + 1 ) [ S [ i ] = = T [ j ] ] f(i,j) += f(i-1,j+1) [S[i]==T[j]] f(i,j)+=f(i1,j+1)[S[i]==T[j]]
如果要放到结尾,如果此时前 i i i个还没有超出后 m − j + 1 m-j+1 mj+1个的长度,有
f ( i , j ) = f ( i , j − 1 ) [ i ≤ m − j + 1 且 S [ i ] = = T [ j + i − 1 ] ] f(i,j) = f(i,j-1) [i \leq m-j+1 且 S[i] == T[j+i-1]] f(i,j)=f(i,j1)[imj+1S[i]==T[j+i1]]
否则可以直接放到结尾
f ( i , j ) = f ( i , j − 1 ) [ i > m − j + 1 ] f(i,j) = f(i,j-1)[i \gt m-j+1] f(i,j)=f(i,j1)[i>mj+1]

注意点

初始化要将 f ( 0 , 1 ) f(0,1) f(0,1) f ( 0 , n + 1 ) f(0,n+1) f(0,n+1)设为 1 1 1,因为 f ( 1 , n ) f(1,n) f(1,n)转移时会用到 f ( 0 , n + 1 ) f(0,n+1) f(0,n+1)

代码

#include<bits/stdc++.h>
#define ll long long
#define N 3005
#define mod 998244353
#define rep(i,a,n) for (int i=a;i<=n;i++)
#define per(i,a,n) for (int i=n;i>=a;i--)
#define inf 0x3f3f3f3f
#define pb push_back
#define mp make_pair
#define lowbit(i) ((i)&(-i))
#define VI vector<int>
using namespace std;
char s[N],t[N];
int n,m,f[N][N]; 
int main(){
	//freopen(".in","r",stdin);
	//freopen(".out","w",stdout);
	scanf("%s%s",s+1,t+1);
	n = strlen(s+1);m = strlen(t+1);
	rep(j,1,n+1) f[0][j] = 1;
	rep(i,1,n){
		rep(j,1,n){
			if(j>m||s[i]==t[j]) f[i][j] = (f[i][j]+f[i-1][j+1])%mod;
			if(i <= m-j+1){
				if(s[i]==t[j+i-1]) f[i][j] = (f[i][j]+f[i-1][j])%mod;
			}else{
				f[i][j] = (f[i][j]+f[i-1][j])%mod;
			}
			//cout << i << ' ' << j << ' ' << f[i][j] << endl;
		}
	}
	int ans = 0;
	rep(i,m,n){
		ans = (ans+f[i][1])%mod; 
	}
	cout << ans << endl;
	return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值