luogu4591 碱基序列 题解

分析

\(f_{i,j}\) 为使用了 \(i\) 个串,匹配到了 \(S\) 的前 \(j\) 位的方案数。 \[ f_{i,j} = \sum_{S[i-m,i] = S_0} f_{i-1,i-m} \] 其中 \(S_0\) 表示一个匹配串,\(S[i-m,i]\) 是这个长度为 \(m\) 的匹配串的长度。

可以用 KMP 算法快速求出匹配串 \(S_0\)\(S\) 中出现的所有位置,最终答案为 \(\sum_{i=0}^n f_{k,i}\)

CODE

#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N=1e4+5, mod=1e9+7;
int n, m, k, ans, cur, nxt[N], f[105][N];
char s[N], p[N];
int read() {
	int a=0, f=1; char c=getchar();
	while(!isdigit(c)) {
		if(c=='-') f=-1;
		c=getchar();
	}
	while(isdigit(c)) a=a*10+c-'0', c=getchar();
	return a*f;
}
void kmp(int k) {
	nxt[1]=0;
	for(int i=2,j=0;i<=m;++i) {
		while(j&&p[i]!=p[j+1]) j=nxt[j];
		if(p[i]==p[j+1]) ++j;
		nxt[i]=j;
	}
	for(int i=1,j=0;i<=n;++i) {
		while(j&&s[i]!=p[j+1]) j=nxt[j];
		if(s[i]==p[j+1]) ++j;
		if(j==m) (f[k][i]+=f[k-1][i-m])%=mod, j=nxt[j];
	}
}
signed main() {
	k=read();
	scanf("%s",s+1), n=strlen(s+1);
	for(int i=0;i<=n;++i) f[0][i]=1;
	for(int i=1;i<=k;++i) {
		int q=read();
		while(q--) {
			scanf("%s",p+1);
			m=strlen(p+1);
			kmp(i);
		}
	}
	for(int i=0;i<=n;++i) (ans+=f[k][i])%=mod;
	printf("%lld\n",ans);
}

luogu4591 碱基序列 题解
https://yozora0908.github.io/2022/lg4591-solution/
作者
yozora0908
发布于
2022年8月12日
许可协议