P3966 [TJOI2013]单词

题目链接:https://www.luogu.org/problemnew/show/P3966

题目描述

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

输入输出格式

输入格式:

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

输出格式:

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

输入输出样例

输入样例#1: 复制

  1. 3
  2. a
  3. aa
  4. aaa
输出样例#1: 复制

  1. 6
  2. 3
  3. 1

说明

数据范围

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

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

题解:

这个题其实问的是一个单词在其它单词中出现的次数,题意有点不清晰吧= =

一个单词若在其它单词中出现,那么其它单词的那一条链上,至少会有一个fail指针指向这个单词的末尾,表面这个单词为目前结点的后缀。

那么我们可以考虑将fail指针翻转,构成一个fail树,那么若统计A单词在其它单词中的出现次数,就直接看以A为根的子树一共有多少个结点就行了。

总体思路就是这样,由于单词可能会重合,并且某些单词可能为另一些单词的前缀,那么我们首先可以记录一共有多少个单词经过单词A的尾节点,假设记为v,那么说明现在他作为前缀的情况有v个了。

之后便根据后面的结点的fail指针从下往上进行更新,来统计作为后缀的情况(注意这里必须从下往上才能保证正确性,并且时间复杂度也比较低),具体的方法就是根据bfs序来进行更新,因为bfs序越大的,那么说明它的深度肯定在更下面,反正不会在上面= =

代码如下:

  1. #include <bits/stdc++.h>
  2. using namespace std;
  3. typedef long long ll;
  4. const int N = 1e6+;
  5. int n,tot;
  6. char s[N];
  7. int num[N],Q[N];
  8. queue <int> q;
  9. struct Aho_Corasick{
  10. int Size;
  11. int ch[N][];
  12. int val[N];
  13. int fail[N];
  14. void init(){
  15. Size=-;
  16. newnode();
  17. }
  18. int newnode(){
  19. memset(ch[++Size],,sizeof(ch[]));
  20. fail[Size]=;
  21. return Size;
  22. }
  23. void insert(char *s,int id){
  24. int l=strlen(s);
  25. int u=;
  26. for(int i=;i<l;i++){
  27. int idx=s[i]-'a';
  28. if(!ch[u][idx]) ch[u][idx]=newnode();
  29. u=ch[u][idx];
  30. num[u]++;
  31. }
  32. val[id]=u;
  33. }
  34. void Getfail(){
  35. while(!q.empty()) q.pop();
  36. for(int i=;i<;i++){
  37. if(ch[][i]) q.push(ch[][i]);
  38. }
  39. while(!q.empty()){
  40. int cur=q.front();q.pop();
  41. Q[++tot]=cur;
  42. for(int i=;i<;i++){
  43. if(ch[cur][i]){
  44. fail[ch[cur][i]]=ch[fail[cur]][i];
  45. q.push(ch[cur][i]);
  46. }else{
  47. ch[cur][i]=ch[fail[cur]][i];
  48. }
  49. }
  50. }
  51. }
  52. }ac;
  53. int main(){
  54. cin>>n;
  55. ac.init();
  56. for(int i=;i<=n;i++){
  57. scanf("%s",s);
  58. ac.insert(s,i);
  59. }
  60. ac.Getfail();
  61. for(int i=tot;i>=;i--) num[ac.fail[Q[i]]]+=num[Q[i]];
  62. for(int i=;i<=n;i++){
  63. printf("%d\n",num[ac.val[i]]);
  64. }
  65. return ;
  66. }

洛谷P3966 [TJOI2013]单词(fail树性质)的更多相关文章

  1. 洛谷P3966 [TJOI2013]单词(AC自动机)

    题目描述 小张最近在忙毕设,所以一直在读论文.一篇论文是由许多单词组成但小张发现一个单词会在论文中出现很多次,他想知道每个单词分别在论文中出现了多少次. 输入输出格式 输入格式: 第一行一个整数N,表 ...

  2. [洛谷P3966][TJOI2013]单词

    题目大意:有$n$个字符串,求每个字符串在所有字符串中出现的次数 题解:$AC$自动机,每个节点被经过时$sz$加一,每一个字符串出现次数为其$fail$树子树$sz$和 卡点:$AC$自动机根节点为 ...

  3. 洛谷P3966 [TJOI2013]单词(后缀自动机)

    传送门 统计单词出现次数……为啥大家都是写AC自动机的嘞……明明后缀自动机也能做的说…… 统计出现次数这个就直接按长度排序然后做个dp就好,这是SAM的板子的要求啊,不提了 然后考虑怎么让所有串之间隔 ...

  4. BZOJ3172 & 洛谷3966 [Tjoi2013]单词 【fail树】

    3172: [Tjoi2013]单词 Time Limit: 10 Sec  Memory Limit: 512 MB Submit: 4293  Solved: 2083 [Submit][Stat ...

  5. 洛谷P2412 查单词 [trie树 RMQ]

    题目背景 滚粗了的HansBug在收拾旧英语书,然而他发现了什么奇妙的东西. 题目描述 udp2.T3如果遇到相同的字符串,输出后面的 蒟蒻HansBug在一本英语书里面找到了一个单词表,包含N个单词 ...

  6. bzoj 3172: [Tjoi2013]单词 fail树

    题目大意: 一篇论文是由许多单词组成,现在想知道每个单词分别在论文中出现多少次. 题解: 我们首先考虑fail指针的含义 如果fail[x] = y,那么我们就知道y作为x的后缀在x中出现了一次 所以 ...

  7. P3966 [TJOI2013]单词

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

  8. 洛谷 P3384 【模板】树链剖分-树链剖分(点权)(路径节点更新、路径求和、子树节点更新、子树求和)模板-备注结合一下以前写的题目,懒得写很详细的注释

    P3384 [模板]树链剖分 题目描述 如题,已知一棵包含N个结点的树(连通且无环),每个节点上包含一个数值,需要支持以下操作: 操作1: 格式: 1 x y z 表示将树从x到y结点最短路径上所有节 ...

  9. 洛谷p3384【模板】树链剖分题解

    洛谷p3384 [模板]树链剖分错误记录 首先感谢\(lfd\)在课上调了出来\(Orz\) \(1\).以后少写全局变量 \(2\).线段树递归的时候最好把左右区间一起传 \(3\).写\(dfs\ ...

随机推荐

  1. VMware SDK使用指南

    刚开始用VMware官方推荐的SDK,真的是又臭又长,代码结构不清晰,易读性差.后来VMware的同学给推荐了一款开源的SDK,一上手感觉工作效率提高了100倍!推荐大家使用~. 该SDK对VMwar ...

  2. TW实习日记:第19天

    今天一早上改完信息门户的代码之后,发现接口又出了问题,查了半天都不知道,原来又是网端的问题...真是心累啊,调整了一些细节样式,以及终于把企业微信的消息推送功能做完了.关键就在于有个表存放微信id的字 ...

  3. 十分钟掌握pandas(pandas官方文档翻译)

    十分钟掌握pandas 文档版本:0.20.3 这是一个对pandas简短的介绍,适合新用户.你可以在Cookbook中查看更详细的内容. 通常,我们要像下面一样导入一些包. In [1]: impo ...

  4. opencv-学习笔记(3)

    opencv-学习笔记(3) 这章讲了 图像加法 opencv测试效率 IPYTHON测试效率 图像加法 cv2.add() 要求,两图片必须大小类型相同 然后是图像混合cv2.addWeighted ...

  5. ServiceStack.Ormlit 使用Insert的时候自增列不会被赋值

    Insert签名是这样的,将第2个参数设置为true就会返回刚插入的自增列ID了,然后可以手工赋值到对象上面去 public static long Insert<T>(this IDbC ...

  6. 官方文档 恢复备份指南二 Getting Started with RMAN

    本章对RMAN进行基本的熟悉和了解   1.Overview of the RMAN Environment    RMAN运行时需要的最小环境:      target database       ...

  7. 使用 letter-space 后文字不能居中解决

    letter-space:2em; text-align: center; 使用letter-space后和上面的字体对比明显没有居中: 选定元素后发现,每个字后面都被加了2em,不是不能居中而是因为 ...

  8. Ubuntu 配置 Android 开发 环境

    . 果断换Ubuntu了, Ubuntu的截图效果不好, 不能设置阴影 ... 作者 : 万境绝尘 转载请注明出处 : http://blog.csdn.net/shulianghan/article ...

  9. (一)Model的产生及处理

    MVC的概念其实最早可以追溯到很久很久以前,并不是WEB开发过程中所首创, 但是,MVC也适合WEB上的开发,并真正的在WEB开发领域广泛应用.MVC的第一个字母M是Model,承载着View层和Co ...

  10. 《学习OpenCV》课后习题解答3

    题目:(P104) 创建一个大小为100*100的三通道RGB图像.将它的元素全部置0.使用指针算法以(20,5)与(40,20)为项点绘制一个绿色平面. 解答: #include "cv. ...