fzu 2246(ac 自动机)

fzu 2246(ac 自动机)

题意:

某一天YellowStar学习了AC自动机,可以解决多模式匹配问题。YellowStart当然不会满足于此,它想进行更深入的研究。

YellowStart有一个母串\(S\),以及\(m\)个询问串\(T\),它发现如果把母串删除掉一个子串,把剩余的串按原先顺序拼接起来,某些询问串\(T\)就可能出现在这个新的母串中。

现在,对于第\(i\)个询问串\(T_i\),YellowStar想知道,母串最多可以删除多长的子串,使得该询问串出现在新的母串的子串中。

\(|S| <= 1e5\)
$\sum{|T_i|} <= 1e5 $

思路:利用ac自动机处理出每个查询串的每个前缀在S中最先出现的位置 和 每个后缀在S中最后出现的位置,取
\(max(sufpos[i+1] - prepos[i] - 1)\)即可

具体的做法 是将所有询问串 正着一遍插入ac自动机,对于串S 类似于找子串的方式更新当前位置匹配的所有前缀,然后再反着插入做一遍即可

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<iostream>
#include<queue>
#define LL long long
using namespace std;

const int N = 1e5 + 10;
char S[N],P[N],tmp[N],S_r[N];
int m, tot;
int len[N],st[N];
int pre_id[N],suf_id[N];
int pre_pos[N],suf_pos[N];
const int SIZE = 26;
const int MAXNODE = 1e5 + 10;

struct AC{
    int ch[MAXNODE][SIZE];
    int f[MAXNODE],last[MAXNODE],val[MAXNODE];
    int sz;
    void init(){sz = 1;memset(ch[0],0,sizeof(ch[0]));}
    int idx(char c){return c - 'a';}
    int _insert(char *s, int st,int len,int *p){
        int u = 0;
        for(int i = 0;i < len;i++){
            int c = idx(s[i + st]);
            if(!ch[u][c]){
                memset(ch[sz],0,sizeof ch[sz]);
                val[sz] = 0;
                ch[u][c] = sz++;
            }
            u = ch[u][c];
            val[u] = 1;
            p[i + st] = u;
        }
        return u;
    }
    void getFail(){
        queue<int> q;
        f[0] = 0;
        for(int c = 0;c < SIZE;c++){
            int u = ch[0][c];
            if(u){
                f[u] = 0;
                q.push(u);
                last[u] = 0;
            }
        }
        while(!q.empty()){
            int r = q.front();q.pop();
            for(int c = 0;c < SIZE;c++){
                int u = ch[r][c];
                if(!u){ch[r][c] = ch[f[r]][c];continue;}
                q.push(u);
                int v = f[r];
                while(v && !ch[v][c]) v = f[v];
                f[u] = ch[v][c];
                last[u] = val[f[u]]?f[u]:last[f[u]];
            }
        }
    }
    void up(int u,int x,int *p){
        if(!u) return ;
        if(p[u] == -2) p[u] = x;
        up(last[u],x,p);
    }
    void Find(char *s,int *p){
        int len = strlen(s), u = 0;
        pre_pos[u] = -1;
        for(int i = 0;i < len;i++){
            int c = idx(s[i]);
            u = ch[u][c];
            up(u,i,p);
        }
    }
}ac;
int main(){
    int T;
    scanf("%d",&T);
    while(T--){
        scanf("%s",P);
        scanf("%d",&m);
        tot = 0;
        for(int i = 0;i < m;i++){
            scanf("%s",tmp);
            len[i] = strlen(tmp);
            st[i] = tot;
            for(int j = 0;j < len[i];j++) S[j + tot] = tmp[j];
            reverse(tmp,tmp + len[i]);
            for(int j = 0;j < len[i];j++) S_r[j + tot] = tmp[j];
            tot += len[i];
        }
        for(int i = 0;i < tot;i++) pre_pos[i] = suf_pos[i] = -2;
        ac.init();
        for(int i = 0;i < m;i++) ac._insert(S,st[i],len[i],pre_id);
        ac.getFail();
        ac.Find(P,pre_pos);
        ac.init();
        for(int i = 0;i < m;i++) ac._insert(S_r,st[i],len[i],suf_id);
        ac.getFail();
        int tlen = strlen(P);
        reverse(P,P + tlen);
        ac.Find(P,suf_pos);
        for(int i = 0;i < m;i++){
            int ans = -1;
            int stt = st[i],ll = len[i];
            if(pre_pos[pre_id[stt + ll - 1]] != -2) ans = max(ans, tlen - pre_pos[pre_id[stt + ll - 1]] - 1);
            if(suf_pos[suf_id[stt + ll - 1]] != -2) ans = max(ans, tlen - suf_pos[suf_id[stt + ll - 1]] - 1);
            for(int j = 0;j + 1 < ll;j++){
                int a = pre_pos[pre_id[j + stt]];
                int b = suf_pos[suf_id[ll - j - 2 + stt]];
                if(a != -2 && b != -2 && tlen - b -1 - a - 1 >= 1) ans = max(ans,tlen - b - 1 - a - 1);
            }
            printf("%d\n",ans);
        }
    }
    return 0;
}


posted @ 2017-10-24 19:17  jiachinzhao  阅读(175)  评论(0编辑  收藏  举报