zoukankan      html  css  js  c++  java
  • 【洛谷】3966:[TJOI2013]单词【AC自动机】【fail树】

    P3966 [TJOI2013]单词
    题目描述
    小张最近在忙毕设,所以一直在读论文。一篇论文是由许多单词组成但小张发现一个单词会在论文中出现很多次,他想知道每个单词分别在论文中出现了多少次。

    输入输出格式
    输入格式:

    第一行一个整数N,表示有N个单词。接下来N行每行一个单词,每个单词都由小写字母(a-z)组成。(N≤200)

    输出格式:

    输出N个整数,第i行的数表示第i个单词在文章中出现了多少次。

    说明
    数据范围
    30%的数据, 单词总长度不超过10^3

    100%的数据,单词总长度不超过10^6

    Solution

    解法也是挺简单的,首先肯定是建出ac自动机。

    然后我们考虑fail指针的含义,fail[u]到根节点是u到根节点串的后缀,也就是以fail[u]为结尾的串在u中出现了cnt[u]次...

    所有的fail都是这样的,所以反向建fail指针变成fail树,统计子树和更新cnt,cnt[u]就是每个u为结尾的串出现的次数了。

    在bfs的时候存下遍历顺序,最后倒着更新就可以了。

    #include<bits/stdc++.h>
    #define LL long long
    using namespace std;
    string s[1000005];
    int n;
    LL ans[1000005], cnt[1000005];
    int son[1000005][27], fail[1000005], tail, las[1000005];
    void insert(string a, int opt) {
        int len = a.length();
        int nd = 0;
        for(int i = 0; i < len; i ++) {
            int t = a[i] - 'a' + 1;
            if(!son[nd][t])    son[nd][t] = ++ tail;
            nd = son[nd][t];
            cnt[nd] ++;
        }
        las[opt] = nd;
    }
    int Q[1000005], t;
    void get_fail() {
        queue < int > q;
        Q[++t] = 0;
        for(int i = 1; i <= 26; i ++)    if(son[0][i])    fail[son[0][i]] = 0, q.push(son[0][i]);
        while(!q.empty()) {
            int u = q.front(); q.pop();
            for(int i = 1; i <= 26; i ++) {
                if(son[u][i])    fail[son[u][i]] = son[fail[u]][i], q.push(son[u][i]), Q[++t] = son[u][i];
                else            son[u][i] = son[fail[u]][i];
            }
        }
    }
    int main() {
        scanf("%d", &n);
        for(int i = 1; i <= n; i ++) {
            cin >> s[i];
            insert(s[i], i);
        }
        get_fail();
        for(int i = t; i; i --) {
            int now = Q[i];
            cnt[fail[now]] += cnt[now];
        }
        for(int i = 1; i <= n; i ++)
            printf("%lld
    ", cnt[las[i]]);
        return 0;
    }
    
  • 相关阅读:
    spring mvc中的@PathVariable
    JSP禁用缓存的方式 response.setHeader( "Pragma", "no-cache" ); setDateHeader("Expires", 0);
    request.getSession(true)和request.getSession(false)的区别
    Spring Mvc中DispatcherServlet和Servlet的区别小结
    web.xml中load-on-startup的作用
    Spring MVC过滤器-字符集过滤器(CharacterEncodingFilter)
    web.xml配置中的log4jRefreshInterval
    web.xml中webAppRootKey
    关于tolua的使用
    关于#pragma pack
  • 原文地址:https://www.cnblogs.com/NoTimepleasssse/p/9826473.html
Copyright © 2011-2022 走看看