P11030 『DABOI Round 1』Blessings Repeated 题解

题面

首先我们注意到 \(\lvert T \rvert\) 很小,所以可以考虑将 \(T\) 拆分为若干个段,并钦定每一段都只被同一个 \(S\) 包含。那么我们需要先处理出对于 \(T\) 的每一个子段,在 \(S\) 中作为子序列出现的次数。这个可以DP来做,我们设 \(f_{i,l,r}\) 表示 \(S\) 的前 \(i\) 位中有多少个子序列和 \(T\) 的第 \(l\)\(r\) 位相同。转移也非常简单:

\[f_{i,l,r}= \begin{aligned} \begin{equation} \begin{cases} f_{i-1,l,r}&(s_i\ne t_r) \\ f_{i-1,l,r}+1&(s_i=t_r,l=r)\\ f_{i-1,l,r}+f_{i-1,l,r-1}&(s_i=t_r,l\ne r) \end{cases} \end{equation} \end{aligned} \]

现在我们考虑统计答案,直接dfs就可以了,当我们搜索出一种拆分将 \(T\) 拆成了 \(p\) 段,第 \(i\) 段从 \(l_i\)\(r_i\) ,那么对答案的贡献应该是:

\[{k\choose m}\prod_{i=1}^m f_{n,l_i,r_i} \]

code:

代码
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N=5e3+10,mod=998244353;
ll f[N][12][12],S,T,inv[12],ans,k;
char s[N],t[12];
ll qp(ll x,ll y)
{
	ll res=1;
	while(y)
	{
		if(y&1) (res*=x)%=mod;
		(x*=x)%=mod,y>>=1;
	}
	return res;
} 
ll C(ll x)
{
	ll res=1;
	for(int i=0;i<x;i++) (res*=(k-i)%mod)%=mod;
	return res*inv[x]%mod;
}
void dfs(int l,int pos,ll res)
{
	if(l>T) return (ans+=res*C(pos))%=mod,void();
	for(int r=l;r<=T;r++) dfs(r+1,pos+1,res*f[S][l][r]%mod);
}
int main()
{
	cin>>k;inv[1]=1;
	for(int i=2;i<=10;i++) inv[i]=inv[i-1]*qp(i,mod-2)%mod;
	scanf("%s%s",s+1,t+1);
	S=strlen(s+1),T=strlen(t+1); 
	for(int i=1;i<=S;i++)
		for(int l=1;l<=T;l++)
			for(int r=l;r<=T;r++)
			{
				f[i][l][r]=f[i-1][l][r];
				if(s[i]==t[r]) (f[i][l][r]+=(l==r?1:f[i-1][l][r-1]))%=mod;
			}
	dfs(1,0,1);
	cout<<ans;
	return 0;
} 
posted @ 2025-04-16 15:46  Re_Star  阅读(9)  评论(0)    收藏  举报