zoukankan      html  css  js  c++  java
  • bzoj 3172 [Tjoi2013]单词(fail树,DP)

    【题目链接】

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

    【题意】

           题目的意思是这样的,给若干个单词,求每个单词在这一堆单词中的出现次数。 出题人语文水平高

          

    【思路】

          

      AC自动机. fail树

      AC自动机中的fail指针指向该串的一个后缀,将fail指针反向后得到一棵fail树,利用getFail后的bfs序在树上进行DP统计出现次数。

      在fail树上,父节点对应字符串是其子结点对应字符串的极大后缀。我们用sum[u]记录一个结点u被几个单词结点所经过,插入时顺便统计一下即可。设pos[i]为单词i在自动机上所对应的尾节点,那么这时候sum[pos[i]]是否为i的答案呢?不是。因为可能出现有一个字符串为abbabc,而i是abc的情况,这时候abc作为后缀出现但是并没有计数,对于结点u,我们应该将fail树上u->root路径上的所有节点的sum+=sum[u],这步操作只需要递推一下,这时候的sum[pos[i]]才是i的答案。

      感觉与SAM中的p=>p->fa的思路挺像的。

    【代码】

     1 #include<cstdio>
     2 #include<cstring>
     3 using namespace std;
     4 
     5 const int N = 1e6+10;
     6 
     7 struct ACauto {
     8     int sz,ch[N][26],sum[N],q[N],pos[N],f[N];
     9     void init() {
    10         sz=1;
    11         memset(ch[0],0,sizeof(ch[0]));
    12     }
    13     void insert(char* s,int rank) {
    14         int u=0;
    15         for(int i=0;s[i];i++) {
    16             int c=s[i]-'a';
    17             if(!ch[u][c]) {
    18                 memset(ch[sz],0,sizeof(ch[sz]));
    19                 ch[u][c]=sz++;
    20             }
    21             u=ch[u][c];
    22             sum[u]++;
    23         }
    24         pos[rank]=u;
    25     }
    26     void get_Fail() {
    27         int front=1,rear=1;        //a pos for 0
    28         f[0]=1; q[0]=1;
    29         for(int i=0,p;i<26;i++)
    30             if(p=ch[0][i]) f[p]=0,q[rear++]=p;
    31         while(front!=rear) {
    32             int qr=q[front++];
    33             for(int c=0;c<26;c++) {
    34                 int u=ch[qr][c];
    35                 if(!u) continue;
    36                 q[rear++]=u; int v=f[qr];
    37                 while(v&&!ch[v][c]) v=f[v];
    38                 f[u]=ch[v][c];
    39             }
    40         }
    41         for(int i=rear-1;i>=0;i--)
    42             sum[f[q[i]]]+=sum[q[i]];
    43     }
    44 }ac;
    45 
    46 int n;
    47 char s[N];
    48 
    49 int main() {
    50     scanf("%d",&n);
    51     ac.init();
    52     for(int i=1;i<=n;i++) {
    53         scanf("%s",s);
    54         ac.insert(s,i);
    55     }
    56     ac.get_Fail();
    57     for(int i=1;i<=n;i++)
    58         printf("%d
    ",ac.sum[ac.pos[i]]);
    59     return 0;
    60 }
  • 相关阅读:
    KVC之-setValue:forKey:方法实现原理与验证
    李洪强iOS开发之iOS社区收集
    跟着百度学PHP[15]-会话控制session的工作机制
    代码审计学习之文件操作漏洞
    中间人攻击——ARP欺骗的原理、实战及防御
    跟着百度学PHP[14]-PDO的预处理语句2
    跟着百度学PHP[14]-PDO的预处理语句1
    跟着百度学PHP[14]-PDO之Mysql的事务处理2
    跟着百度学PHP[14]-PDO之Mysql的事务处理1
    跟着百度学PHP[14]-PDO的错误处理模式&PDO执行SQL
  • 原文地址:https://www.cnblogs.com/lidaxin/p/5202660.html
Copyright © 2011-2022 走看看