首页 > 其他 > 详细

[BZOJ3413]匹配

时间:2018-06-19 21:12:14      阅读:279      评论:0      收藏:0      [点我收藏+]

bzoj

description

技术分享图片

sol

首先你要求出\(s_i\)第一次匹配的位置。(或者是没有匹配位置)
然后问题就大致转化为了:求\(s_i\)和原串中第一次匹配位置之前的所有后缀的\(lcp\)之和。(有一些小细节就自己\(yy\)一下吧)
这个问题显得不是那么好做,考虑把这个问题转化一下,改为求\(s_i\)的每个前缀在匹配位置之前的出现次数。
然后看上去就很简单了?对\(SAM\)线段树合并\(endpos\)集合,然后一边跑匹配一边线段树区间查询。复杂度\(O(\sum len\times\log n)\)

code

#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
int gi(){
    int x=0,w=1;char ch=getchar();
    while ((ch<'0'||ch>'9')&&ch!='-') ch=getchar();
    if (ch=='-') w=0,ch=getchar();
    while (ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
    return w?x:-x;
}
const int N = 2e5+5;
struct seg{int ls,rs,sz;}t[N*40];
int n,q,tot=1,last=1,tr[N][10],fa[N],len[N],rt[N],Node,tong[N],a[N];
char s[N];
void extend(int c){
    int v=last,u=++tot;last=u;
    len[u]=len[v]+1;
    while (v&&!tr[v][c]) tr[v][c]=u,v=fa[v];
    if (!v) fa[u]=1;
    else{
        int x=tr[v][c];
        if (len[x]==len[v]+1) fa[u]=x;
        else{
            int y=++tot;
            memcpy(tr[y],tr[x],sizeof(tr[y]));
            fa[y]=fa[x];fa[x]=fa[u]=y;len[y]=len[v]+1;
            while (v&&tr[v][c]==x) tr[v][c]=y,v=fa[v];
        }
    }
}
void modify(int &x,int l,int r,int p){
    if (!x) x=++Node;++t[x].sz;
    if (l==r) return;int mid=l+r>>1;
    if (p<=mid) modify(t[x].ls,l,mid,p);
    else modify(t[x].rs,mid+1,r,p);
}
int merge(int x,int y){
    if (!x||!y) return x|y;
    int z=++Node;t[z].sz=t[x].sz+t[y].sz;
    t[z].ls=merge(t[x].ls,t[y].ls);
    t[z].rs=merge(t[x].rs,t[y].rs);
    return z;
}
int find(int x,int l,int r){
    if (l==r) return l;int mid=l+r>>1;
    if (t[t[x].ls].sz) return find(t[x].ls,l,mid);
    else return find(t[x].rs,mid+1,r);
}
int query(int x,int l,int r,int ql,int qr){
    if (l>=ql&&r<=qr) return t[x].sz;
    int mid=l+r>>1,res=0;
    if (ql<=mid) res+=query(t[x].ls,l,mid,ql,qr);
    if (qr>mid) res+=query(t[x].rs,mid+1,r,ql,qr);
    return res;
}
int main(){
    n=gi();scanf("%s",s+1);
    for (int i=1;i<=n;++i) extend(s[i]-'0'),modify(rt[last],1,n,i);
    for (int i=1;i<=tot;++i) ++tong[len[i]];
    for (int i=1;i<=n;++i) tong[i]+=tong[i-1];
    for (int i=1;i<=tot;++i) a[tong[len[i]]--]=i;
    for (int i=tot;i>1;--i) rt[fa[a[i]]]=merge(rt[fa[a[i]]],rt[a[i]]);
    q=gi();while (q--){
        scanf("%s",s+1);int l=strlen(s+1),now=1,lst;
        long long ans=0;
        for (int i=1;i<=l;++i) now=tr[now][s[i]-'0'];
        if (now) lst=find(rt[now],1,n),ans=lst-l;
        else lst=-1,ans=n;
        now=1;
        for (int i=1;i<=l;++i){
            now=tr[now][s[i]-'0'];
            if (now) ans+=query(rt[now],1,n,1,lst==-1?n:lst-l+i);
        }
        printf("%lld\n",ans);
    }
    return 0;
}

[BZOJ3413]匹配

原文:https://www.cnblogs.com/zhoushuyu/p/9200987.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!