zoukankan      html  css  js  c++  java
  • 洛谷 P3966 [TJOI2013]单词(AC自动机 || Fail树)

    题目链接:https://www.luogu.com.cn/problem/P3966

    对于这一道题,可以对所有单词建出AC自动机,然后将每个节点x和fail[x]之间连一条边,这样可以形成一个树:fail树。

    根据fail树的一些性质:

    ①:每个节点都是一个字符串的前缀,并且每个字符串的前缀一定在fail树上有一个节点

    ②:fail树的大小等于AC自动机的大小,fail树的根就是AC自动机的根

    ③:每个节点的父亲都是这个节点的最长后缀,每个节点的所有祖先是这个节点的所有后缀

    ------>尤其是第3个性质,我们可以把这个问题转化成:

    只要将每个单词加入字典树,中间经过的节点sum值全部++,然后建立AC自动机求出fail树,从根节点开始DFS,对于树上每个节点,将它和它子树中所有的sum加起来就是该节点单词出现总次数。

    AC代码:

     1 #include<cstdio>
     2 #include<iostream>
     3 #include<cstring>
     4 #include<algorithm>
     5 #include<queue>
     6 using namespace std;
     7 const int N=1000000+100;
     8 int fail[N],ch[N][26],vis[N],ans[N],sum[N],head[N];
     9 char str[N];
    10 int cnt,tot;
    11 struct node{
    12     int to,next;
    13 }edge[N*2];
    14 void init(){
    15     memset(head,-1,sizeof(head));
    16     tot=0;
    17 }
    18 void add(int u,int v){
    19     edge[tot].next=head[u];
    20     edge[tot].to=v;
    21     head[u]=tot++;
    22 }
    23 void insert(char *s,int v){
    24     int u=0;
    25     int len=strlen(s);
    26     for(int i=0;i<len;i++){
    27         int id=s[i]-'a';
    28         if(!ch[u][id]) ch[u][id]=++cnt;
    29         u=ch[u][id];
    30         sum[u]++;
    31     }
    32     vis[v]=u;
    33 }
    34 void get_fail(){
    35     int u=0;
    36     queue<int> q;
    37     for(int i=0;i<26;i++){
    38         if(ch[u][i]){
    39             q.push(ch[u][i]);
    40             fail[ch[u][i]]=u;
    41             add(0,ch[u][i]);
    42         }
    43     }
    44     while(!q.empty()){
    45         int u=q.front();q.pop();
    46         for(int i=0;i<26;i++){
    47             if(ch[u][i]){
    48                 q.push(ch[u][i]);
    49                 fail[ch[u][i]]=ch[fail[u]][i];
    50                 add(fail[ch[u][i]],ch[u][i]);
    51             }
    52             else ch[u][i]=ch[fail[u]][i];
    53         }
    54     }
    55 }
    56 void DFS(int u,int fa){
    57     for(int i=head[u];i!=-1;i=edge[i].next){
    58         int v=edge[i].to;
    59         if(v==fa) continue;
    60         DFS(v,u);
    61         sum[u]+=sum[v];
    62     }
    63 }
    64 int main(){
    65     int n;
    66     scanf("%d",&n);
    67     for(int i=1;i<=n;i++){
    68         scanf("%s",str);
    69         insert(str,i);
    70     }
    71     init();
    72     get_fail();
    73     DFS(0,-1);
    74     for(int i=1;i<=n;i++) printf("%d
    ",sum[vis[i]]);
    75     return 0;
    76 }
    AC代码
  • 相关阅读:
    CSS知识总结一
    Html知识总结一
    转:B/S和C/S结构的区别
    转:理解本真的 REST 架构风格
    转载:简洁明了说明RESTful架构是什么
    名词理解
    转: 如何理解API,API 是如何工作的
    WEB的理解
    开关按钮的实现
    ssm学习之ssm框架详解
  • 原文地址:https://www.cnblogs.com/New-ljx/p/12404463.html
Copyright © 2011-2022 走看看