zoukankan      html  css  js  c++  java
  • 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;
    }
    
    
    
  • 相关阅读:
    VS创建MVC出错解决方法
    服务器环境~某个页面无法访问的处理
    SSIS 处理错误的方法
    SSIS 数据流的执行树和数据管道
    利用SSIS的ForcedExecutionResult 属性 和CheckPoint调试Package
    处于同一域中的两台SQL Server 实例无法连接
    SQL Server 日期和时间类型
    Lookup 转换组件
    约束2:主键约束,唯一约束和唯一索引
    查询语句影响的行数
  • 原文地址:https://www.cnblogs.com/jiachinzhao/p/7353259.html
Copyright © 2011-2022 走看看