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. 为什么说session依赖cookie,以及cookie的常用知识

    session的用法 session在Flask中通常用做设置某些页面的权限,比如某些页面必须要登录才可以看到,登录的信息或标志就放到session中.它的使用过程如下: 在整个flask工程的启动文 ...

  2. [JSON].connectionValue()

    语法: [JSON].connectionValue() 说明: 将对象的所有键值接连成新的字符串值 返回: [String] 示例: Set a = toJson() c = Array(1,2,3 ...

  3. leetcode7_C++整数反转

      给出一个 32 位的有符号整数,你需要将这个整数中每位上的数字进行反转. 示例 1: 输入: 输出:  示例 2: 输入: - 输出: - 示例 3: 输入: 输出: 注意: 假设我们的环境只能存 ...

  4. C++字符串拼接和输入

    一 .char类型字符串以空字符结尾 1.以空字符结尾,空字符被写作\0,其ASCII码为0,用来标记字符串的结尾. char dog[4]={'a','b','c','d'}   //不是一个字符串 ...

  5. 开源自动驾驶仿真平台 AirSim (1) - Unreal Engine

    AirSim 官方Github: https://github.com/Microsoft/AirSim AirSim 是微软的开源自动驾驶仿真平台(其实它还能做很多事情,这里主要用于自动驾驶仿真研究 ...

  6. [2018 ACL Short and System] 对话系统

    Short Paper(s) 1.  Task-oriented Dialogue System for Automatic Diagnosis. (Cited by 0) Zhongyu Wei, ...

  7. vmware安装64位系统“此主机支持 Intel VT-x,但 Intel VT-x 处于禁用状态”的问题

    虚拟机使用的是VMware Workstation,并且首次在虚拟机体验64 位系统.在新建好虚拟机,运行时候就出现了VMware Workstation 的提醒:此主机支持 Intel VT-x,但 ...

  8. docker最佳实践-----美团点评的分享

    美团点评容器平台简介 本文介绍美团点评的Docker容器集群管理平台(以下简称“容器平台”).该平台始于2015年,是基于美团云的基础架构和组件而开发的Docker容器集群管理平台.目前该平台为美团点 ...

  9. POJ 2986 A Triangle and a Circle(三角形和圆形求交)

    Description Given one triangle and one circle in the plane. Your task is to calculate the common are ...

  10. nodejs在linux环境下安装更新方式

    #检查是否已经安装 rpm -qa | grep python #查版本 python #最好是重新安装 Python推荐版本( >= v2.5.0 & < 3.0.0 ),否则影 ...