题面:https://www.lydsy.com/JudgeOnline/problem.php?id=3413
题解:
首先考虑匹配次数的意义。可以看出匹配的过程就是拿\(A\)串的所有前缀
和\(B\)串一一匹配。考虑\(A\)串的每一位。设当前位一共被匹配了\(f[i]\)次,
那么答案即为\(\sum\) \(f[i]\)。
考虑\(f[i]\)的组成。它包括了两个部分:匹配成功的次数和失配次数。
其中,失配次数是可以单独计算的。
我们可以给\(A\)串建立SAM,用\(B\)串在上面跑。
如果跑到了0号节点,说明整个匹配过程是失败的,所以失配次数为\(n\);
否则,失配次数就是跑到的那个节点的endpos最靠左的那个节点。
至于如何记这个endpos,可以用线段树合并。具体实现就是先对所有SAM上
的节点拓扑排序,然后从大到小合并上去即可。
现在考虑匹配成功的次数。考虑\(B\)串在\(A\)串的SAM上跑的过程。
每次跑到一个非根节点,这个节点的线段树上存有当前位置所有的endpos。
设失配次数为\(x\),那么当前节点能计入贡献的只有endpos<=\(x\)的那些
(注意这里的endpos代表的是一个前缀的一个子串),其他的那些因为已经匹配完了,
所以不计入贡献。
时间复杂度:\(O(SlogS)\)(\(S\)指的是\(B\)串总长)
代码:
#include
using namespace std;
#define re register int
#define F(x,y,z) for(re x=y;x<=z;x++)
#define FOR(x,y,z) for(re x=y;x>=z;x--)
typedef long long ll;
#define I inline void
#define IN inline int
#define C(x,y) memset(x,y,sizeof(x))
#define STS system("pause")
templateI read(D &res){
res=0;register D g=1;register char ch=getchar();
while(!isdigit(ch)){
if(ch=='-')g=-1;
ch=getchar();
}
while(isdigit(ch)){
res=(res<<3)+(res<<1)+(ch^48);
ch=getchar();
}
res*=g;
}
const int INF=1e9+7;
char c[101000];
int n,m,leng,sum,root[202000],lc[4040000],rc[4040000],w[4040000];
I modi(int &k,int l,int r,int x){
if(!k)k=++sum;w[k]++;
if(l==r)return;
re mid=(l+r)>>1;
if(x<=mid)modi(lc[k],l,mid,x);
else modi(rc[k],mid+1,r,x);
}
IN merge(int x,int y){
if(!x&&!y)return 0;
if(!x)return y;
if(!y)return x;
re now=++sum;
lc[now]=merge(lc[x],lc[y]);rc[now]=merge(rc[x],rc[y]);w[now]=w[x]+w[y];
return now;
}
IN ques_min(int k,int l,int r){
if(l==r)return l;
re mid=(l+r)>>1;
if(w[lc[k]])return ques_min(lc[k],l,mid);
else return ques_min(rc[k],mid+1,r);
}
inline ll ques_sum(int k,int l,int r,int lim){
if(!k||l>lim)return 0;
if(l==r||r<=lim)return w[k];
re mid=(l+r)>>1;
return ques_sum(lc[k],l,mid,lim)+ques_sum(rc[k],mid+1,r,lim);
}
namespace SAM{
ll ans;
int len[202000],link[202000],ch[202000][10],buc[202000],sa[202000],p,q,las,cur,tot,cle;
I add(int x){
len[cur=++tot]=len[las]+1,p=las,las=cur;
while(p&&!ch[p][x])ch[p][x]=cur,p=link[p];
if(!p){link[cur]=1;return;}
q=ch[p][x];
if(len[p]+1==len[q]){link[cur]=q;return;}
cle=++tot;len[cle]=len[p]+1,link[cle]=link[q];
memcpy(ch[cle],ch[q],sizeof(ch[q]));
while(p&&ch[p][x]==q)ch[p][x]=cle,p=link[p];
link[q]=link[cur]=cle;
}
I init(){
tot=las=1;
F(i,1,n)add(c[i]-'0'),modi(root[cur],1,n,i);
F(i,1,tot)buc[len[i]]++;
F(i,1,tot)buc[i]+=buc[i-1];
FOR(i,tot,1)sa[buc[len[i]]--]=i;
FOR(i,tot,1)if(sa[i]!=1)root[link[sa[i]]]=merge(root[link[sa[i]]],root[sa[i]]);
}
I ques(){
p=1;q=INF;
F(i,1,leng)p=ch[p][c[i]-'0'];
if(!p)ans=n;
else{
q=ques_min(root[p],1,n);
ans=q-leng;
}
p=1;
F(i,1,leng){
p=ch[p][c[i]-'0'];
if(!p)break;
ans+=ques_sum(root[p],1,n,q+i-leng);
}
printf("%lld\n",ans);
}
}
int main(){
read(n);
scanf("%s",c+1);
SAM::init();
read(m);
while(m--){
scanf("%s",c+1);
leng=strlen(c+1);
SAM::ques();
}
return 0;
}