Obsessive String - CodeForces 494 B KMP+dp

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

Input consists of two lines containing strings s and t (1 ≤ |s|, |t| ≤ 105). Each string consists of lowercase Latin letters.

Output

Print the answer in a single line.

Sample test(s)
input
ababa
aba
output
5
input
welcometoroundtwohundredandeightytwo
d
output
274201
input
ddd
d
output
12


题意:给你两个字符串,问第一个字符串可以有多少种方式拆分出子串,使得得到的所有子串都包含第二个字符串。

思路:dp[i]表示前在第一个字符串中前i个字符可以拆分出来的方式。对于第r个字符,如果至少为l-r使得其包含第二个字符串,那么dp[r]=dp[i-1]+  dp[l-1]+1  +dp[l-2]+1 +...+dp[0]+1;每次表示最后的那些字符组成一个拆分出来的子串。合并之后为dp[r]=sum[l-1]+l;

AC代码如下:

#include<cstdio>
#include<cstring>
using namespace std;
typedef long long ll;
char str1[100010];
char str2[100010];
int f[100010],val[200010];
int n,m;
ll dp[100010],sum[100010],MOD=1e9+7;
void find()
{ int i,j=0;
  for(i=0;i<n;i++)
  { while(j && str2[j]!=str1[i])
     j=f[j];
    if(str2[j]==str1[i])
     j++;
    if(j==m)
      val[i+1]=i-m+2;
  }
}
void getfail()
{ int i,j;
  memset(f,0,sizeof(f));
  for(i=1;i<m;i++)
  { j=f[i];
    while(j && str2[j]!=str2[i])
     j=f[j];
    if(str2[j]==str2[i])
     f[i+1]=j+1;
    else
     f[i+1]=0;
  }
}
int main()
{
    int t,i,j,k;
    scanf("%s",str1);
    scanf("%s",str2);
    n=strlen(str1);
    m=strlen(str2);

    getfail();
    find();

    for(i=1;i<=n;i++)
       if(val[i]==0)
         val[i]=val[i-1];
    for(i=1;i<=n;i++)
    {
        dp[i]=dp[i-1];
        if(val[i]>0)
          dp[i]+=sum[val[i]-1]+val[i];
        dp[i]%=MOD;
        sum[i]=(sum[i-1]+dp[i])%MOD;
    }
    printf("%I64d\n",dp[n]);
}







评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值