P8256字符串 题解

传送门

考虑\(DP\)

记状态 \(f_{i,j,st,en}\) 表示现在枚举到第 \(i\) 个字符,匹配了 \(j\) 个字符,要在前面删 \(st\) 个字符,在后面删 \(en\) 个字符的方案数

不难发现 \(f_{n+1,m,0,0}=1\)

状态转移有

\(s_i='-'\) 时,

\(f_{i,j,st,en}=f_{i+1,j,st-1,en}+f_{i+1,j,st,en-1}\)

\(s_i=0/1\) 时,

\(f_{i,j,st,en}=f_{i+1,j,st,en+1}\)

\(en=0\)\(j=0\)\(f_{i,0,st,0}+=f_{i+1,0,st+1,0}\)

\(j!=m\)\(s_i=t_{j+1}\)\(en=0\)\(f_{i,j,st,0}+=f_{i+1,j+1,st,0}\)

考虑优化:

因为可以通过 \(i,j,st\) 推断出 \(en\) 所以 \(en\) 可以不要,只记三个状态 \(f_{i,j,st}\)

注意:当想思路清晰一些时,用记忆化搜索会比 \(DP\) 更好

上代码:

#include<bits/stdc++.h>
using namespace std;
const int N=405;
const int mod=1e9+7;
int T,n,m,len;
char s[N],t[N];
int f[N][N][N];
int dfs(int wz,int gs,int st,int en)
{
	if(wz>n) return gs==m&&!st&&!en;
	if(f[wz][gs][st]!=-1) return f[wz][gs][st];
	long long res=0;
	if(s[wz]=='-')
	{
		if(st) res=(res+dfs(wz+1,gs,st-1,en))%mod;
		if(en) res=(res+dfs(wz+1,gs,st,en-1))%mod;
	}
	else
	{
		res=dfs(wz+1,gs,st,en+1)%mod;
		if(!gs&&!en) res=(res+dfs(wz+1,0,st+1,0))%mod;
		if(gs!=m&&s[wz]==t[gs+1]&&!en) res=(res+dfs(wz+1,gs+1,st,0))%mod;
	}
	return f[wz][gs][st]=res%mod;
}
int main()
{
	scanf("%d",&T);
	while(T--)
	{
		memset(f,-1,sizeof f);
		scanf("%d %d %s %s",&n,&m,s+1,t+1);
		len=0;
		printf("%d\n",dfs(1,0,0,0));
	}
	return 0;
}

后记:真唐吧,两小时想不出这道题

posted @ 2023-10-30 21:31  傻阙的缺  阅读(18)  评论(0)    收藏  举报