一、题目
二、解法
先对 S S S建出后缀自动机,然后先判断 T T T在 S S S中是否出现过,对于自动机每个点我们维护一个最小的 e n d p o s endpos endpos,就可以知道 T T T在 S S S第一次出现的位置了。
我们可以先对答案赋一个初始值,根据 T T T在 S S S中是否出现过而定,如果出现过,设出现位置( e n d p o s endpos endpos)为 F F F,那么答案的初始值应该是 F − ∣ T ∣ F-|T| F−∣T∣。否则应该是 n n n,就考虑失配拿一下的答案。
然后我们在此把 T T T放在 S S S上匹配,设匹配到了一个长度 i i i,我们要看现在匹配的部分的出现次数,把它计入答案中,也就是当前点 p p p的 e n d p o s endpos endpos在 [ 1 , F − ∣ T ∣ + i ] [1,F-|T|+i] [1,F−∣T∣+i]中出现个数,用线段树合并来维护即可。
时间复杂度 O ( ∑ ∣ T ∣ log n ) O(\sum|T|\log n) O(∑∣T∣logn),贴个代码 q w q qwq qwq。
#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
const int M = 200005;
int read()
{
int x=0,flag=1;
char c;
while((c=getchar())<'0' || c>'9') if(c=='-') flag=-1;
while(c>='0' && c<='9') x=(x<<3)+(x<<1)+(c^48),c=getchar();
return x*flag;
}
int n,m,k,tot,f[M],cnt,last,len[M],fa[M],ch[M][10];
int Index,mi[M],rt[M],ls[20*M],rs[20*M],sum[20*M];char s[M];
struct edge
{
int v,next;
edge(int V=0,int N=0) : v(V) , next(N) {}
} e[2*M];
void ins(int &x,int l,int r,int id)
{
x=++Index;
sum[x]=1;
if(l==r) return ;
int mid=(l+r)>>1;
if(mid>=id) ins(ls[x],l,mid,id);
else ins(rs[x],mid+1,r,id);
}
void add(int c)
{
int p=last,np=last=++cnt;
ins(rt[np],1,n,mi[np]=len[np]=len[p]+1);
for(; p && !ch[p][c]; p=fa[p]) ch[p][c]=np;
if(!p) fa[np]=1;
else
{
int q=ch[p][c];
if(len[q]==len[p]+1) fa[np]=q;
else
{
int nq=++cnt;
fa[nq]=fa[q];
memcpy(ch[nq],ch[q],sizeof ch[q]);
len[nq]=len[p]+1;
fa[q]=fa[np]=nq;
for(; p && ch[p][c]==q; p=fa[p]) ch[p][c]=nq;
}
}
}
int merge(int x,int y)
{
if(!x || !y) return x|y;
int p=++Index;
sum[p]=sum[x]+sum[y];
ls[p]=merge(ls[x],ls[y]);
rs[p]=merge(rs[x],rs[y]);
return p;
}
int ask(int i,int l,int r,int L,int R)
{
if(!i || L>r || l>R || L>R) return 0;
if(L<=l && r<=R) return sum[i];
int mid=(l+r)>>1;
return ask(ls[i],l,mid,L,R)+ask(rs[i],mid+1,r,L,R);
}
void dfs(int u)
{
for(int i=f[u]; i; i=e[i].next)
{
int v=e[i].v;
if(v==fa[u]) continue;
dfs(v);
rt[u]=merge(rt[u],rt[v]);
mi[u]=min(mi[u],mi[v]);
}
}
int main()
{
cnt=last=1;
n=read();scanf("%s",s);
for(int i=0;i<n;i++) add(s[i]-'0');
for(int i=2;i<=cnt;i++)
{
if(!mi[i]) mi[i]=n+1;
e[++tot]=edge(i,f[fa[i]]),f[fa[i]]=tot;
e[++tot]=edge(fa[i],f[i]),f[i]=tot;
}
dfs(1);
m=read();
while(m--)
{
scanf("%s",s),k=strlen(s);
int p=1,F=0;long long ans=0;
for(int i=0;i<k;i++)
{
int c=s[i]-'0';
if(!ch[p][c]) {F=0;break;}
p=ch[p][c];F=mi[p];
}
if(!F) ans=n;
else ans=F-k;
p=1;
for(int i=0;i<k;i++)
{
int c=s[i]-'0';
if(!ch[p][c]) break;
p=ch[p][c];
ans+=ask(rt[p],1,n,1,(!F)?n:F-k+i+1);
//注意是从0开始的,所以还要加个1
}
printf("%lld\n",ans);
}
}