CF494B Obsessive String(KMP+DP)

来源:互联网 发布:淘宝花溪都是什么牌子 编辑:程序博客网 时间:2024/06/06 09:34

这道题的题目真是太难读了。。。推了半天样例。其实就是让你求合法的集合数目。合法的集合定义为:

1、集合中的所有串都是s的子串,且互不重叠 2、集合中的所有串都含有子串t。

设串s长度为n,串t长度为m,我们首先用kmp在s中匹配t,匹配成功的位置我们打下标记flag[i]=1(s[i-m+1...i]=t[1..m]).

以下角标均针对串s:设dp[i]表示合法且集合中最后一个子串为s[j..i]的集合数目,sum1[i]为dp[1..i]得前缀和,sum2[i]为sum1[1..i]得前缀和。不难发现:如果flag[i]为0,则dp[i]=dp[i-1]。如果flag[i]为1,则dp[i]=i-m+1+sum2[i-m]。证明:若flag[i]=1,说明s[i-m+1...i]=t[1..m],那么s[j..i](j=1..i-m+1)都含有子串t,如果k=1,也就是集合中只有一个串的话,一共有i-m+1种,如果k>=2,那么一个串我们选定s[j..i],能和他匹配的串,因为不能重叠,所以是dp[1]+dp[2]+..+dp[j-1]即sum1[j-1],那么所有的可能就是sum1[1]+sum1[2]...+sum1[i-m],即sum2[i-m]。所以dp[i]=i-m+1+sum2[i-m]

#include <cstdio>#include <cstring>#define ll long long#define N 100100#define mod 1000000007int n,m,fail[N],dp[N],sum1[N],sum2[N];bool flag[N];char s[N],t[N];inline void getfail(){int k=0;fail[1]=0;for(int i=2;i<=m;++i){while(k&&t[k+1]!=t[i]) k=fail[k];if(t[k+1]==t[i]) ++k;fail[i]=k;}}int main(){//freopen("a.in","r",stdin);scanf("%s%s",s+1,t+1);n=strlen(s+1);m=strlen(t+1);getfail();int k=0;for(int i=1;i<=n;++i){while(k&&t[k+1]!=s[i]) k=fail[k];if(t[k+1]==s[i]) ++k;if(k==m) flag[i]=1;}for(int i=1;i<=n;++i){if(flag[i]){dp[i]=(i-m+1+sum2[i-m])%mod;}else dp[i]=dp[i-1];sum1[i]=(sum1[i-1]+dp[i])%mod;sum2[i]=(sum2[i-1]+sum1[i])%mod;}int ans=0;for(int i=1;i<=n;++i) ans=(ans+dp[i])%mod;printf("%d\n",ans);return 0;}


原创粉丝点击