Hamed has recently found a string t and suddenly became quite fond of it. He spent several days trying to find all occurrences of t in other strings he had. Finally he became tired and started thinking about the following problem. Given a string s how many ways are there to extract k ≥ 1 non-overlapping substrings from it such that each of them contains string t as a substring? More formally, you need to calculate the number of ways to choose two sequences a1, a2, ..., ak and b1, b2, ..., bk satisfying the following requirements:
- k ≥ 1
t is a substring of string saisai + 1... sbi (string s is considered as 1-indexed).
As the number of ways can be rather large print it modulo 109 + 7.
Input consists of two lines containing strings s and t (1 ≤ |s|, |t| ≤ 105). Each string consists of lowercase Latin letters.
Print the answer in a single line.
ababa
aba
5
welcometoroundtwohundredandeightytwo
d
274201
ddd
d
12
思路: 首先用KMP求出匹配的位置;
dp[i][j] 变示包含a[i]的匹配分成 j 段的方案,
sum[i][j]是前 i 个字母,分成 j 段的方案(也就是不一定包含a[i])
即 sum[i][j]=sum(dp[k][j]) ; k <= i ;
定义 e[i][j] = sum(sum[k][j]) k <= i ;
如果i不是匹配的节点
dp[i][j]=dp[i-1][j];
如果 i 是匹配的节点;
那么 dp[i][j] = e[i-m][j-1];(j>=2)
dp[i][1]=i-m+2;
即枚举a[i]和谁在一起
先得到下面的转移(假设|a|/|b| < 10)
int ans=0;
if(m==1&&a[0]==b[0])
{
dp[0][1]=1;
sum[0][1]=1;
e[0][1]=1;
ans++;
}
for( i = 1 ; i < n ;i++)
{
for(j = 1 ; j < 10 ;j++)
dp[i][j]=dp[i-1][j] ;
if(vi[i])
{
dp[i][1]=i-m+2;
if(i==m-1);
else
for( j = 2; j < 10 ;j++){
dp[i][j]=(e[i-m][j-1]);
}
}
for(j = 1 ; j < 10 ;j++){
ans+=dp[i][j];
sum[i][j]=sum[i-1][j]+dp[i][j];
e[i][j]=e[i-1][j]+sum[i][j];
}
}
cout << ans << endl;
不过我们发现这样内存和时间都不能承受‘;
观察发现,第二维可以不要;
后面得到的代码是:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
#include<set>
#include<map>
#include<stack>
#include<cmath>
#define LL long long
#define maxn 100010
#define eps 1e-9
#define mod 1000000007
using namespace std;
LL dp[maxn] ,f[maxn];
LL sum[maxn],e[maxn];
char a[maxn],b[maxn] ;
bool vi[maxn] ;
void getNext()
{
int n,j,i;
j=-1;
f[0]=-1;
n=strlen(b) ;
for( i = 1 ; i < n ;i++)
{
while(j>=0&&b[j+1] != b[i])j=f[j] ;
if(b[j+1]==b[i])j++ ;
f[i]=j;
}
}
void KMP()
{
int n,m,i,j;
j=-1;
getNext();
n=strlen(a) ;
m=strlen(b) ;
memset(vi,0,sizeof(vi));
for( i = 0 ; i < n ;i++)
{
while( j >= 0 && b[j+1] != a[i])j=f[j] ;
if(b[j+1]==a[i]) j++ ;
if(j==m-1)
{
vi[i]=true;
}
}
}
int main()
{
int i,n,m,j,k,id;
int T,case1=0,len ;
while(scanf("%s%s",a,b) != EOF)
{
KMP();
n = strlen(a) ;
m = strlen(b) ;
memset(dp,0,sizeof(dp)) ;
memset(sum,0,sizeof(sum)) ;
memset(e,0,sizeof(e));
int ans=0;
if(m==1&&a[0]==b[0])
{
dp[0]=1;
sum[0]=1;
e[0]=1;
ans++;
}
for( i = 1 ; i < n ;i++)
{
dp[i]=dp[i-1] ;
if(vi[i])
{
dp[i]=i-m+2;
if(i==m-1);
else{
dp[i] += e[i-m] ;
dp[i] %= mod;
}
}
ans+=dp[i];
ans%= mod;
sum[i]=sum[i-1]+dp[i];
sum[i] %=mod;
e[i]=e[i-1]+sum[i];
e[i] %= mod;
}
cout << ans << endl;
}
return 0 ;
}