zoukankan      html  css  js  c++  java
  • P3966 [TJOI2013]单词

    P3966 [TJOI2013]单词

    AC自动机

    题意:输入若干个单词,对于每个单词,计算它在所有单词中出现的次数(原题讲的什么鬼)。

    attention:有重复单词,还很多

    显然,我们可以用AC自动机来搞

    但是对每个单词都需要跑一遍要用极大的空间来存-->MLE。

    于是我们想到用一个主串把这些单词拼在一起,中间用特殊符号隔开。这样我们就只要在主串上跑一遍AC自动机就可以了

    但是这样还不够(90pts)

    于是我们就要对AC自动机进行优化(以后都这样写吧qwq)。

    引入一个last指针,保存某节点沿fail指针向前跳最近一个有结尾标记的节点,询问时直接按last指针代替fail指针跳转。搞定

    对于重复单词:用一个pre数组存储某编号对应单词的结尾节点

    end.

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<queue>
    using namespace std;
    struct data{
        int nxt[26],end,fail,last;
    }a[1000002];
    int n,cnt,pre[202];
    long long f[202];
    string q,g;
    inline void Trie_build(int id){
        cin>>q; g=g+"#"+q; //用string方便地加上各个单词
        int u=0,len=q.size();
        for(int i=0;i<len;++i){
            int p=q[i]-'a';
            if(!a[u].nxt[p]) a[u].nxt[p]=++cnt;
            u=a[u].nxt[p];
        }
        if(!a[u].end) a[u].end=id;
        pre[id]=a[u].end; //重复单词处理
    }
    inline void AC_build(){
        queue <int> h;
        for(int i=0;i<26;++i) if(a[0].nxt[i]) h.push(a[0].nxt[i]);
        while(!h.empty()){
            int x=h.front(); h.pop();
            for(int i=0;i<26;++i){
                int &to=a[x].nxt[i];
                if(to){
                    a[to].fail=a[a[x].fail].nxt[i];
                    a[to].last= a[a[to].fail].end ? a[to].fail:a[a[to].fail].last; //last指针优化
                    h.push(to);
                }else to=a[a[x].fail].nxt[i];
            }
        }
    }
    inline void AC_query(){
        int u=0,len=g.size();
        for(int i=0;i<len;++i){
            if(g[i]=='#') {u=0; continue;}
            u=a[u].nxt[g[i]-'a'];
            for(int j=u;j;j=a[j].last) ++f[a[j].end]; //按last指针跳转
        }
        for(int i=1;i<=n;++i) printf("%lld
    ",f[pre[i]]); //输出的是 指向的节点 的编号 的值
    }
    int main(){
        //freopen("P3966.in","r",stdin);
        scanf("%d",&n);
        for(int i=1;i<=n;++i) Trie_build(i);
        AC_build();
        AC_query();
        return 0;
    }
  • 相关阅读:
    QT中的定时器使用
    range()函数常和len()函数一起用于字符串索引。在这里我们要显示每一个元素及其索引值。
    range()的print 《P核》P30
    2.13 带逗号的print语句输出的元素之间自动带个空格
    Python3.x和Python2.x的区别
    print语句默认每行添加一个换行符 来自2.13
    2.12 while循环 print与计数器先后顺序对结果的影响
    函数本地绑定与全局绑定的区别
    字典映射{ :}
    《Python核心编程》P21输入数值字符串→转整型
  • 原文地址:https://www.cnblogs.com/kafuuchino/p/9620216.html
Copyright © 2011-2022 走看看