题意: 给出字符串s,t,找出有多少种方法提取s的若干个子串,且每个子串都含有 t字符串;
思路: 动态规划----先用KMP匹配s和t,记录下匹配成功时的下标。 a[ i ]表示s的前缀 s1s2s3.............si 有多少中方法提取(注意每个提取的最后一个子串都要含有最后一个
字符s[ i ] );最后答案就是 ans = a[1]+a[2]+.............+a[| s |];
O( n )算出a[],当i不是标记下标时,a[i]=a[i-1],否则a[i]=q2[i-|t|]+i-| t |+1; 其中q1 是 a 的前缀和,q2 是 q1 的前缀合;
代码:
#include<iostream>
#include<cstring>
#include <cmath>
#define MOD 1000000007
using namespace std;
typedef long long ll;
const int maxn=1e5+10;
char s[maxn],t[maxn];
ll q1[maxn],q2[maxn],a[maxn],vis[maxn],f[maxn];
int n,m;
void KMP()
{
memset(vis,0,sizeof(vis));
m=strlen(t);
n=strlen(s);
f[0]=0;f[1]=0;
for(int i=1;i<m;i++)
{
int j=f[i];
while(j && t[i]!=t[j]) j=f[j];
f[i+1]=t[i]==t[j]?j+1:0;
}
int j=0;
for(int i=0;i<n;i++)
{
while(j && s[i]!=t[j]) j=f[j];
if(s[i]==t[j]) j++;
if(j==m) vis[i+1]=1;
}
}
int main()
{
ll sum=0;
cin>>s>>t;
KMP();
a[0]=q1[0]=q2[0]=0;
for(int i=1;i<=n;i++)
{
if(!vis[i])
a[i]=a[i-1];
else
{
a[i]=(q2[i-m]+i-m+1)%MOD;
}
q1[i]=(q1[i-1]+a[i])%MOD;
q2[i]=(q2[i-1]+q1[i])%MOD;
}
for(int i=1;i<=n;i++)
sum=(sum+a[i])%MOD;
cout<<sum<<endl;
return 0;
}