• 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
    ",ans);
            }
        }
        return 0;
    }
    
    
    
  • 相关阅读:
    rpm软件包以及rmp命令
    使用ssh-keygen生成密钥对
    从现有的虚拟机创建vagrant box ,再利用新创建的box创建虚拟机
    EXCEL固定行和列
    URL编码
    标准ASCII码
    base64编码
    http学习--URL字符
    浏览器通过http获取服务器资源的过程
    一名程序员过去10年的程序员生涯,给程序员小弟弟小妹妹们的一些总结性忠告
  • 原文地址:https://www.cnblogs.com/jiachinzhao/p/7725289.html
Copyright © 2020-2023  润新知