题目大意:给你两个串,一长一短,如果长串中某个子串和短串完全相同,则这个子串可以被替换成"#",求长串所有的表达形式.......
比如"hehehehe"和"hehe",则有5种情况,"#hehe","he#he","hehe#","##","hehehehe"
首先我们KMP/哈希找出长串中所有可以作为和短串结尾匹配成功后的位置
然后可以得到方程
(不是子串结尾)
(是子串结尾)
至于原因呢,如果它不是子串结尾,那么它不能被替换,所以是
而如果它是子串结尾,它既可以不被替换,即
也可以被替换,那么替换整个短串,转移的地方就是
然后转移一下即可,建议从1开始读入字符串方便转移
#include <cstdio>
#include <algorithm>
#include <cstring>
#define N 100100
#define mod 1000000007
#define ui unsigned int
#define ll long long
using namespace std;
int T,ls,lt;
int ed[N],nxt[N];
ui f[N];
char s[N],t[N];
void get_kmp()
{
int i=1,j=0;
nxt[1]=0;
while(i<=lt)
{
if(j==0||t[i]==t[j])
{
i++;
j++;
nxt[i]=j;
}else{
j=nxt[j];
}
}
}
void KMP()
{
int i=1,j=1;
while(i<=ls)
{
if(j==0||s[i]==t[j])
{
i++;
j++;
}else{
j=nxt[j];
}
if(j==lt+1)
{
ed[i-1]=1;
j=nxt[j];
}
}
}
ui solve()
{
f[0]=1;
for(int i=1;i<=ls;i++)
{
if(ed[i]==1)
{
f[i]=(f[i-lt]+f[i-1])%mod;
}else{
f[i]=f[i-1];
}
}
return f[ls];
}
int main()
{
//freopen("aa.in","r",stdin);
scanf("%d",&T);
for(int i=1;i<=T;i++)
{
memset(nxt,0,sizeof(nxt));
memset(ed,0,sizeof(ed));
memset(f,0,sizeof(f));
scanf("%s",s+1),ls=strlen(s+1);
scanf("%s",t+1),lt=strlen(t+1);
get_kmp();
KMP();
printf("Case #%d: %u\n",i,solve());
}
return 0;
}