• 2017 多校6 String


    多校6 String(ac自动机)

    题意:

    给一本有(n)个单词的字典

    (q)个查询 (pref_i,suff_i) 查询字典里有多少单词前缀匹配(pref_i),后缀同时匹配(suff_i),并且
    (pref_i)(suf_i)不相交

    (0 < n ,q <= 1e5)
    $ sum (|pref_i| + |suff_i|) <= 5e5$
    $ sum |w_i| <= 5e5$
    保证每组查询的前后缀不相交

    思路:

    forever97大神的这个思路很不错,比起题解的做法来说,更加符合字符串的套路吧

    所有查询一起处理,把查询按$suff_i $ * $pref_i $,
    中间用*隔开的形式拼接起来,丢到ac自动机里
    然后对于字典里的每个单词 扩展成两倍,同样中间用 * 隔开,
    在ac自动机里查询有多少个前后缀是该字符串的子串,比较一下长度就可以知道前后缀是否相交

    这样就变成了最简单的在一个文本串中找哪些字符串出现过的问题了

    #include<bits/stdc++.h>
    #define LL long long
    #define P pair<int,int>
    #define lson l,m,rt<<1
    #define rson m+1,r,rt<<1|1
    #define ls rt<<1
    #define rs (rt<<1|1)
    using namespace std;
    int read(){
        int x = 0;
        char c = getchar();
        while(c < '0' || c > '9') c = getchar();
        while(c >= '0' && c <= '9') x = x * 10 + c - 48, c = getchar();
        return x;
    }
    const int SIZE = 27;
    const int MAXNODE = 1e6 + 10;
    const int N = 1e6 + 10;
    char word[N],wo[N];
    char pre[N],suf[N];
    int w_len[N];
    int pos[N];
    int ans[N];
    struct AC{
        int ch[MAXNODE][SIZE];
        int f[MAXNODE],last[MAXNODE],val[MAXNODE],length[MAXNODE];
        int sz;
        void init(){sz = 1;memset(ch[0],0,sizeof(ch[0]));length[0]=0;}
        int idx(char c){return c - 'a';}
        int _insert(char *s,int v){
            int u = 0,len = strlen(s);
            for(int i = 0;i < len;i++){
                int c = idx(s[i]);
                if(!ch[u][c]){
                    memset(ch[sz],0,sizeof ch[sz]);
                    val[sz] = 0;
                    length[sz] = i + 1;
                    ch[u][c] = sz++;
                }
                u = ch[u][c];
            }
            if(!val[u]) {ans[u] = 0,val[u] = v;}
            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 cal(int len,int u){
            if(u) {
                if(length[u] <= len)   ans[u]++;
                cal(len,last[u]);
            }
        }
        void Find(char *s,int l){
            int len = strlen(s),u = 0;
            for(int i = 0;i < len;i++){
                u = ch[u][idx(s[i])];
                if(val[u]) cal(l,u);
                else if(last[u]) cal(l,last[u]);
            }
        }
    }ac;
    int main(){
    
        int T,n,q;
        T = read();
        while(T--){
           n = read(),q = read();
           int total = 0;
           for(int i = 1;i <= n;i++){
            scanf("%s",wo);
            w_len[i] = strlen(wo);
            for(int j = 0;j < w_len[i];j++) word[j + total] = wo[j];
            total += w_len[i];
           }
           ac.init();
           for(int i = 1;i <= q;i++){
                scanf("%s%s",pre,suf);
                int l = strlen(pre),r = strlen(suf);
                suf[r]='z'+1;
                for(int j = 0;j < l;j++) suf[r+1+j] = pre[j];
                suf[l +  r + 1] = '';
                pos[i] = ac._insert(suf,i);
           };
           ac.getFail();
           int now = 0;
           for(int i = 1;i <= n;i++) {
                for(int j = 0;j < w_len[i];j++) pre[j + w_len[i] + 1] = pre[j] = word[now + j];
                pre[w_len[i]] = 'z' + 1;
                pre[2 * w_len[i] + 1] = '';
                ac.Find(pre,w_len[i]+1);
                now += w_len[i];
           }
           for(int i = 1;i <= q;i++) printf("%d
    ",ans[pos[i]]);
        }
        return 0;
    }
    
    
    
  • 相关阅读:
    Daliy Algorithm (dp,模拟)-- day 80
    Daliy Algorithm (dp,堆)-- day 79
    Mybatis一级缓存和二级缓存 Redis缓存
    简单排序
    java一个大接口拆用多线程方式拆分成多个小接口
    集群环境下Shiro Session的管理
    递归和快速排序
    分布式定时任务
    Redis集群架构
    IO流
  • 原文地址:https://www.cnblogs.com/jiachinzhao/p/7353259.html
Copyright © 2020-2023  润新知