BZOJ3413: 匹配
BZOJ3413: 匹配
题目描述
题目分析
我们设询问串为\(t\)从头开始的第一个字符串为\(s[1]\),设在位置\(x\)匹配成功,则题目要求的就是\(\sum_{i=1}^xlcp(s[i],t)\)
可以考虑先对\(s\)建立后缀自动机,然后考虑每一个\(endpos\)类会对答案造成多少贡献。
明显可以发现匹配位置之后的都对答案没有贡献,所以可以使用线段树合并维护\(right\)集合,查询的时候直接查匹配位置前面的部分即可。
是代码呢
#include <bits/stdc++.h>
using namespace std;
const int MAXN=2e5+7;
#define mid ((l+r)>>1)
int n,m,T[MAXN],st[MAXN<<5],L[MAXN<<5],R[MAXN<<5],sz;
char s[MAXN];
inline void modify(int &u,int l,int r,int k)
{
if(!u) u=++sz;
st[u]++;
if(l==r) return;
if(mid>=k) modify(L[u],l,mid,k);
else modify(R[u],mid+1,r,k);
}
inline int query(int u,int l,int r,int dl,int dr)
{
if(dl<=l&&r<=dr) return st[u];
int ans=0;
if(dl<=mid) ans+=query(L[u],l,mid,dl,dr);
if(dr>mid) ans+=query(R[u],mid+1,r,dl,dr);
return ans;
}
inline int merge(int u,int v)
{
if(!u||!v) return u+v;
int rt=++sz;
st[rt]=st[u]+st[v];
L[rt]=merge(L[u],L[v]);R[rt]=merge(R[u],R[v]);
return rt;
}
struct SAM{
int trans[MAXN][27],maxlen[MAXN],fa[MAXN],od[MAXN],pos[MAXN],wt[MAXN];
int cnt,last,p,np,q,nq;
SAM(){last=++cnt;}
inline void insert(int x,int id){
p=last;last=np=++cnt;maxlen[np]=maxlen[p]+1;pos[np]=id;
modify(T[np],1,n,id);
while(!trans[p][x]&&p) trans[p][x]=np,p=fa[p];
if(!p) fa[np]=1;
else {
q=trans[p][x];
if(maxlen[q]==maxlen[p]+1) fa[np]=q;
else {
nq=++cnt;maxlen[nq]=maxlen[p]+1;
pos[nq]=pos[q];
memcpy(trans[nq],trans[q],sizeof(trans[q]));
fa[nq]=fa[q];fa[q]=fa[np]=nq;
while(trans[p][x]==q) trans[p][x]=nq,p=fa[p];
}
}
}
inline void get_right(){
for(int i=1;i<=cnt;i++) wt[maxlen[i]]++;
for(int i=1;i<=n;i++) wt[i]+=wt[i-1];
for(int i=cnt;i;i--) od[wt[maxlen[i]]--]=i;
for(int i=cnt;i>1;i--) T[fa[od[i]]]=merge(T[fa[od[i]]],T[od[i]]),pos[fa[od[i]]]=min(pos[fa[od[i]]],pos[od[i]]);
}
inline int check(){
int now=1;
for(int i=1,l=strlen(s+1);i<=l;i++){
if(trans[now][s[i]-'0']) now=trans[now][s[i]-'0'];
else return -1;
}
return pos[now];
}
}sam;
int main()
{
cin>>n;
scanf("%s",s+1);
for(int i=1;i<=n;i++) sam.insert(s[i]-'0',i);
sam.get_right();
cin>>m;
while(m--){
int ans=0;
scanf("%s",s+1);
int l=strlen(s+1),h=sam.check();
if(h==-1) ans=n;
else ans=h+1-l;
for(int i=1,now=1;i<l;i++){
if(sam.trans[now][s[i]-'0']) now=sam.trans[now][s[i]-'0'];
else break;
if(h==-1) ans+=query(T[now],1,n,1,n);
else ans+=query(T[now],1,n,1,h-l+i);
}
printf("%d\n",ans);
}
}
对于作者转载文章,欢迎继续转载。
对于作者原创文章,请注明出处之后转载。