这道题的题目真是太难读了。。。推了半天样例。其实就是让你求合法的集合数目。合法的集合定义为:
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 1000000007
int 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;
}