BZOJ3413: 匹配
BZOJ3413: 匹配
https://lydsy.com/JudgeOnline/problem.php?id=3413
分析:
- 这题很好啊。
- 首先正着做比较麻烦,考虑转换一下。
- 我们不求\(S\)中每个长度等于\(m\)的匹配长度而是求\(T\)中每个前缀会匹配多少次。
- 这样就非常简单了,先跑一遍正常的匹配求在哪停止匹配。
- 然后后缀树上线段树合并区间求和即可。
代码:
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cstdlib>
#include <cmath>
#include <iostream>
#include <set>
using namespace std;
typedef long long ll;
#define N 200050
#define db(x) cerr<<#x<<" = "<<x<<endl
char w[N],str[N];
int ch[N][10],fa[N],len[N],lst=1,cnt=1,flg[N],n,m;
int root[N],yukari;
int ls[N*20],rs[N*20],siz[N*20],ke[N],ro[N];
void update(int l,int r,int x,int &p) {
if(!p) p=++yukari;
siz[p]++;
if(l==r) return ;
int mid=(l+r)>>1;
if(x<=mid) update(l,mid,x,ls[p]);
else update(mid+1,r,x,rs[p]);
}
int merge(int x,int y) {
if(!x||!y) return x+y;
int p=++yukari;
ls[p]=merge(ls[x],ls[y]);
rs[p]=merge(rs[x],rs[y]);
siz[p]=siz[ls[p]]+siz[rs[p]];
return p;
}
int query(int l,int r,int x,int y,int p) {
if(!p||!siz[p]||x>y) return 0;
if(x<=l&&y>=r) return siz[p];
int mid=(l+r)>>1,re=0;
if(x<=mid) re+=query(l,mid,x,y,ls[p]);
if(y>mid) re+=query(mid+1,r,x,y,rs[p]);
return re;
}
void insert(int x,int id) {
int p=lst,np=++cnt,q,nq;
len[np]=len[p]+1; flg[np]=id; lst=np;
for(;p&&!ch[p][x];p=fa[p]) ch[p][x]=np;
if(!p) fa[np]=1;
else {
q=ch[p][x];
if(len[q]==len[p]+1) fa[np]=q;
else {
nq=++cnt; len[nq]=len[p]+1; flg[nq]=flg[q];
fa[nq]=fa[q]; memcpy(ch[nq],ch[q],sizeof(ch[q]));
fa[np]=fa[q]=nq;
for(;p&&ch[p][x]==q;p=fa[p]) ch[p][x]=nq;
}
}
}
int main() {
scanf("%d%s",&n,w+1);
int i;
for(i=1;i<=n;i++) insert(w[i]-'0',i),update(1,n,i,root[lst]);
for(i=1;i<=cnt;i++) ke[len[i]]++;
for(i=1;i<=cnt;i++) ke[i]+=ke[i-1];
for(i=cnt;i;i--) ro[ke[len[i]]--]=i;
for(i=cnt;i>1;i--) {
int p=ro[i];
root[fa[p]]=merge(root[fa[p]],root[p]);
}
int cas;
scanf("%d",&cas);
while(cas--) {
scanf("%s",str+1);
m=strlen(str+1);
int p=1,flag=1;
for(i=1;i<=m;i++) {
int x=str[i]-'0';
if(ch[p][x]) {
p=ch[p][x];
}else {
flag=0; break;
}
}
ll ans=0;
int pos=flg[p];
if(!flag) pos=n,ans=n;
else ans=pos-m;
p=1;
for(i=1;i<=m;i++) {
int x=str[i]-'0';
if(ch[p][x]) {
p=ch[p][x];
if(!flag) ans+=query(1,n,1,n,root[p]);
else ans+=query(1,n,1,pos-(m-i),root[p]);
}else break;
}
printf("%lld\n",ans);
}
}