• 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;
    }
    
    
    
  • 相关阅读:
    判断用户分辨率调用不同的CSS样式文件
    译文:创建性感的CSS
    CSS控制文字的显示与隐藏时引出的Bug
    设计规范的理想
    浏览器不兼容的源头
    图片垂直居中的使用技巧
    CSS命名规范
    5.2 微格式
    如何在本地使用 Yahoo! BrowserPlus
    如何让 Firefox 2 和 Firefox 3 版本并存
  • 原文地址:https://www.cnblogs.com/jiachinzhao/p/7353259.html
Copyright © 2020-2023  润新知