题目意思让我读了好久,可怜我渣渣英语。 题意大概是 先给你一个串 S 然后再给你一个串 T ,那么如果一个集合,这个集合里面有一些串 分别为 a1,a2,a3,a4...ax
如果 这些串都属于 S的子串并且 这些串不能含有相同的第某个字符,即是不能重复 且 T 也是这些串每个串的子串,那么这个集合就是一个合法集合,问有多少个合法集合
举个例子吧 ababa 和 aba 那么符合条件的集合 有5个 分别 是 { aba } ,{abab} ,{ababa}. {baba},{aba}.
首先 考虑 DP[I] 表示 以 i 为起点 必须包含 i 的到串尾的 合法集合的个数
那么先用KMP记录出 以I 开头 长为 |T| 刚好匹配 记为 fg[i]=1; i从 0到 n-1;
然后 当 fg[i] 为 0 时 就为 dp[i] =dp[i+1]
如果 当 fg[i] 为 1 那么 dp[i]=n-i-m+1 dp[i]+=dp[i+m]+d[i+m+1]*2+dp[i+m+2]*3...
后面这些东西 可以用 前缀和的前缀和 统计
代码如下
#include<iostream>
#include<algorithm>
#include<stdio.h>
#include<string.h>
using namespace std;
typedef long long LL;
#define mod 1000000007
#define NN 200000
LL dp[NN+10];
char mo[NN+10],s[NN+10];
int next[NN+10],fg[NN+10];
LL sum1[NN+10],sum2[NN+10];
void get_next(int m)
{
next[0]=next[1]=0;
for(int i=1;i<m;i++)
{
int j=next[i];
while(j && mo[i]!=mo[j]) j=next[j];
next[i+1]= mo[i]==mo[j]?j+1:0;
}
}
void Find(int n,int m)
{
int j=0;
for(int i=0;i<n;i++)
{
while(j && mo[j]!=s[i]) j=next[j];
if(mo[j]==s[i]) j++;
if(j==m)
{
j=next[j];
fg[i-m+1]=1;
}
}
}
int main()
{
while(scanf("%s",s)!=EOF)
{
scanf("%s",mo);
int m=strlen(mo);
int n=strlen(s);
memset(fg,0,sizeof(fg));
memset(sum1,0,sizeof(sum1));
memset(sum2,0,sizeof(sum2));
memset(dp,0,sizeof(dp));
get_next(m);
Find(n,m);
for(int i=n-1;i>=0;i--)
{
if(fg[i]==1)
{
dp[i]+=n-i-m+1;
dp[i]%=mod;
if(i+m <= n)
dp[i]=(dp[i]+sum2[i+m])%mod;
sum1[i]=(sum1[i+1]+dp[i])%mod;
sum2[i]=(sum2[i+1]+sum1[i])%mod;
}
else
{
dp[i]=dp[i+1];
sum1[i]=(sum1[i+1]+dp[i])%mod;
sum2[i]=(sum2[i+1]+sum1[i])%mod;
}
}
LL ans=0;
for(int i=0;i<n;i++)
{
ans=(ans+dp[i])%mod;
}
printf("%lld\n",ans);
}
return 0;
}