zoukankan      html  css  js  c++  java
  • BZOJ3172:[TJOI2013]单词——题解

    https://www.lydsy.com/JudgeOnline/problem.php?id=3172

    某人读论文,一篇论文是由许多单词组成。但他发现一个单词会在论文中出现很多次,现在想知道每个单词分别在论文中出现多少次。

    fail树的棵题。

    朴素想法就是建立AC自动机,每个串都匹配一遍,这样显然TLE。

    但是实际上我们就是相当于查询一个单词x在另一个单词y内出现了多少次。

    对于上面这个问题,一种朴素想法是AC自动机,把y单词的所有结点的fail都跑一遍,看看有没有指向x末尾的,有答案++。

    其实我们只用到了fail指针,所以不如我们把fail提出来重新建树,减少状态。

    令cnt[i]为0~i的路径拼起来字符串出现次数。

    这样我们建立了fail树,从下往上累加cnt即可,最终答案就是查询单词的末尾记录的cnt。

    我们因为只进行了一次dfs,比之前查询n次的效率显然高到不知道哪里去了。

    #include<algorithm>
    #include<iostream>
    #include<cstring>
    #include<cctype>
    #include<cstdio>
    #include<vector>
    #include<queue>
    #include<cmath>
    using namespace std;
    typedef long long ll;
    const int N=220;
    const int S=1e6+5;
    inline int read(){
        int X=0,w=0;char ch=0;
        while(!isdigit(ch)){w|=ch=='-';ch=getchar();}
        while(isdigit(ch))X=(X<<3)+(X<<1)+(ch^48),ch=getchar();
        return w?-X:X;
    }
    struct trie{
        int a[26],fail;
    }tr[S];
    struct node{
        int to,nxt;
    }e[S];
    int m,tot,cnt[S],ed[N],sum,head[S];
    char s[S];
    queue<int>q;
    inline void add(int u,int v){
        e[++sum].to=v;e[sum].nxt=head[u];head[u]=sum;
    }
    void insert(int id){
        int len=strlen(s),now=0;
        for(int i=0;i<len;i++){
            int c=s[i]-'a';
            if(!tr[now].a[c])tr[now].a[c]=++tot;
            now=tr[now].a[c];
            cnt[now]++;
        }
        ed[id]=now;
    }
    void getfail(){
        tr[0].fail=0;
        for(int i=0;i<26;i++){
            int u=tr[0].a[i];
            if(u){
                tr[u].fail=0;
                q.push(u);
                add(0,u);
            }
        }
        while(!q.empty()){
            int u=q.front();q.pop();
            for(int i=0;i<26;i++){
                if(tr[u].a[i]){
                    int v=tr[u].a[i];
                    tr[v].fail=tr[tr[u].fail].a[i];
                    q.push(v);
                    add(tr[v].fail,v);
                }else tr[u].a[i]=tr[tr[u].fail].a[i];
            }
        }
        return;
    }
    void dfs(int u){
        for(int i=head[u];i;i=e[i].nxt){
            int v=e[i].to;
            dfs(v);
            cnt[u]+=cnt[v];
        }
    }
    int main(){
        int n;scanf("%d",&n);
        for(int i=1;i<=n;i++){
            scanf("%s",s);
            insert(i);
        }
        getfail();
        dfs(0);
        for(int i=1;i<=n;i++)printf("%d
    ",cnt[ed[i]]);
        return 0;
    }

    +++++++++++++++++++++++++++++++++++++++++++

    +本文作者:luyouqi233。               +

    +欢迎访问我的博客:http://www.cnblogs.com/luyouqi233/ +

    +++++++++++++++++++++++++++++++++++++++++++

  • 相关阅读:
    Linux运维笔记
    回到顶部过渡js代码
    好想你红枣
    鼠标点击区域问题
    ie6 hover 子元素无效bug
    IE6和7下text-indent导致inline-block标签消失的bug
    星星评分js代码
    洛谷P3147 [USACO16OPEN]262144 2048 合并 倍增 动归 递推
    洛谷P1114 “非常男女”计划
    洛谷P1108 低价购买 动态规划
  • 原文地址:https://www.cnblogs.com/luyouqi233/p/8997360.html
Copyright © 2011-2022 走看看