BZOJ3413: 匹配

BZOJ3413: 匹配


題目描述

傳送門php

題目分析

咱們設詢問串爲\(t\)從頭開始的第一個字符串爲\(s[1]\),設在位置\(x\)匹配成功,則題目要求的就是\(\sum_{i=1}^xlcp(s[i],t)\)c++

能夠考慮先對\(s\)創建後綴自動機,而後考慮每個\(endpos\)類會對答案形成多少貢獻。spa

明顯能夠發現匹配位置以後的都對答案沒有貢獻,因此能夠使用線段樹合併維護\(right\)集合,查詢的時候直接查匹配位置前面的部分便可。code

是代碼呢

#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);
    }
}
相關文章
相關標籤/搜索