zoukankan      html  css  js  c++  java
  • P3796 【模板】AC自动机(加强版)

    题目描述

    NNN 个由小写字母组成的模式串以及一个文本串 TTT 。每个模式串可能会在文本串中出现多次。你需要找出哪些模式串在文本串 TTT 中出现的次数最多。

    输入输出格式

    输入格式:

    输入含多组数据。

    每组数据的第一行为一个正整数 NNN ,表示共有 NNN 个模式串, 1≤N≤1501 leq N leq 1501N150 。

    接下去 NNN 行,每行一个长度小于等于 707070 的模式串。下一行是一个长度小于等于 10610^6106 的文本串 TTT 。

    输入结束标志为 N=0N=0N=0 。

    输出格式:

    对于每组数据,第一行输出模式串最多出现的次数,接下去若干行每行输出一个出现次数最多的模式串,按输入顺序排列。

    输入输出样例

    输入样例#1: 
    2
    aba
    bab
    ababababac
    6
    beta
    alpha
    haha
    delta
    dede
    tata
    dedeltalphahahahototatalpha
    0
    输出样例#1: 
    4
    aba
    2
    alpha
    haha

    Solution:

      额,还是比较板子的AC自动机。

      略过AC自动机的构建(本题最好搞个后缀链接的优化),我们只需要在匹配的时候,记录一下各字符串出现的次数,最后比较一下就好了,坑点是除了字符串其它所有数组都要清0(trie,end,fail,last,cnt,num)。

      其实本题原题蓝书上有,那里会有重复的模式串,而本题没有,重复的模式串会在trie树中覆盖掉前面出现的字符串的end,可以思考一下加加强版,实现方法很多。

    代码:

    #include<bits/stdc++.h>
    #define il inline
    #define ll long long
    #define For(i,a,b) for(int (i)=(a);(i)<=(b);(i)++)
    #define Bor(i,a,b) for(int (i)=(b);(i)>=(a);(i)--)
    using namespace std;
    const int N=10305,M=1000005;
    int trie[N][26],cnt,end[N],n,num[155],last[N],fail[N];
    char s[155][72],t[M];
    
    il void cler(){
        memset(trie,0,sizeof(trie));
        memset(num,0,sizeof(num));
        memset(end,0,sizeof(end));
        memset(fail,0,sizeof(fail));
        memset(last,0,sizeof(last));
        cnt=0;
    }
    
    il void insert(char *s,int id){
        int len=strlen(s)-1,p=0,x;
        For(i,0,len){
            x=s[i]-'a';
            if(!trie[p][x])trie[p][x]=++cnt;
            p=trie[p][x];
        }
        end[p]=id;
    }
    
    il void bfs(){
        queue<int>q;
        For(i,0,25) if(trie[0][i]) fail[trie[0][i]]=0,q.push(trie[0][i]);
        while(!q.empty()){
            int u=q.front();q.pop();
            For(i,0,25){
                int v=trie[u][i];
                if(v) fail[v]=trie[fail[u]][i],last[v]=end[fail[v]]?fail[v]:last[fail[v]],q.push(v);
                else trie[u][i]=trie[fail[u]][i];
            }
        }
    }
    
    il void query(char *t){
        int len=strlen(t)-1,p=0,ans=0;
        For(i,0,len){
            p=trie[p][t[i]-'a'];
            for(int j=p;j;j=last[j]) if(end[j]) num[end[j]]++;
        }
        For(i,1,n) ans=max(num[i],ans);
        printf("%d
    ",ans);
        For(i,1,n) if(num[i]==ans) puts(s[i]);
    }
    
    int main(){
        while(scanf("%d",&n)==1){
            if(!n) exit(0);
            cler();
            For(i,1,n) scanf("%s",s[i]),insert(s[i],i);
            bfs();
            scanf("%s",t);
            query(t);
        }
        return 0;
    }
  • 相关阅读:
    jQuery使用(十一):jQuery实例遍历与索引
    jQuery使用(十):jQuery实例方法之位置、坐标、图形(BOM)
    BOM:浏览器对象模型之浏览器剖析入门
    源码来袭:bind手写实现
    源码来袭:call、apply手写实现与应用
    浏览器UI多线程及JavaScript单线程运行机制的理解
    jQuery使用(九):队列及实现原理、基于队列模拟实现animate()
    原生JavaScript运动功能系列(五):定时定点运动
    原生JavaScript运动功能系列(四):多物体多值链式运动
    原生JavaScript运动功能系列(三):多物体多值运动
  • 原文地址:https://www.cnblogs.com/five20/p/9443815.html
Copyright © 2011-2022 走看看