Description
Solution
题意简化以后就是:在b串的同构中,有多少个可以按顺序匹配多个串。
我们可以先把a串拆开,每个做一遍KMP的预处理,
倍长b串,枚举b串的开头,依次匹配过去,
每次匹配的时候,记录一下上一次匹配失败的位置,直接从上次匹配失败的地方开始匹配;成功是也记录一下,判断一下当前可不可以用那个匹配成功的去匹配当前的位置。
复杂的:
O(nm)
;
Code
#include<cstdio>
#include<cstring>
#define fo(i,a,b) for(int i=a;i<=b;i++)
using namespace std;
const int N=100500;
int m,n,ans;
char b[N*2],a[N];
int nx[N],A[N][2],A0;
int B[N],L[N];
int max(int a,int b){return a<b?b:a;}
bool ss(int q,int l,int r)
{
l=max(l,L[q]);
if(A0==1&&l!=r+1)return 0;
if(q>A0 && l<=r+1)return 1;
if(r-l<A[q][1]-A[q][0])return 0;
if(q==A0 && a[n]!='*')
{
int w=r-(A[q][1]-A[q][0])-A[q][0];
fo(i,A[q][0],A[q][1])if(a[i]!=b[w+i])return 0;
return 1;
}
int j=A[q][0]-1;
if(B[q]>=l)return ss(q+1,B[q]+A[q][1]-A[q][0],r);
fo(i,l,r)
{
while(j>=A[q][0]&&a[j+1]!=b[i])j=nx[j];
if(a[j+1]==b[i])j++;
if(j>=A[q][1])
{
bool z=ss(q+1,i+1,r);
B[q]=z*(i-j+2);
return z;
}
}
L[q]=max(L[q],r-j);
return 0;
}
int main()
{
int q,w;char ch;
for(ch=getchar();ch<='z'&&ch>='a'||ch=='*';ch=getchar())a[++n]=ch;
a[n+1]=a[0]='*';
for(;!(ch<='z'&&ch>='a');ch=getchar());
for(;ch<='z'&&ch>='a';ch=getchar())b[++m]=ch;
fo(i,1,m)b[m+i]=b[i];
fo(i,1,n)if(a[i]!='*')
{
if(a[i-1]=='*')A[++A0][0]=i;
A[A0][1]=i;
}
fo(I,1,A0)
{
int j=A[I][0]-1;
nx[A[I][0]]=j;
fo(i,A[I][0]+1,A[I][1])
{
while(j>=A[I][0]&&a[j+1]!=a[i])j=nx[j];
if(a[j+1]==a[i])j++;
nx[i]=j;
}
}
ans=0;
if(!A0)ans=m;else
for(int i=1,j=0;i-j<=m;i++)
if(a[1]=='*')ans+=ss(1,i,i+m-1);else
{
while(j>=A[1][0]&&a[j+1]!=b[i])j=nx[j];
if(a[j+1]==b[i])j++;
if(j>=A[1][1])
{
ans+=ss(2,i+1,i-j+m);
j=nx[j];
}
}
printf("%d\n",ans);
return 0;
}