题目大意:

给定n个字符串连成了一篇文章,问每个字符串在这篇文章中出现的次数,可重复覆盖

这里ac自动机和后缀数组都可以做

当然后缀数组很容易就解决,但是相对时间消耗高

这里就只讲ac自动机了

将每个字符串放入ac自动机中,这里需要记录到达每个ac自动机上的节点出现这个状态有多少次

而我们添加字符串进入的时候,应该是把经过的每个节点的val都++,说明这个字符串多出现了一次这个值

然后因为自己用字符串在ac自动机上走肯定是到达离root最近的点,也就是说有很多的点会不断通过fail指针指向他,而这些点都是包含了这个字符串的

那也就是说我们需要考虑 val[fail[i]] += val[i]

这里一定是需要从最底层的点不断fail上来,我们需要找到一个合适的更新val点的顺序

可以考虑在我们构建后缀自动机的时候我们采用的是利用队列bfs的过程,那也就是说进入的点是符合最大长度从小到大的性质的

而fail指向的总是比它长度更小的点,所以根据进入队列的点的逆顺序来更新val即可

也就是每次点进队列都 que[cnt++] = u;

最后

for(int i=sz-1 ; i>0 ; i--)
  val[fail[que[i]]]+=val[que[i]];

 #include <cstdio>
#include <cstring>
#include <queue>
#include <vector>
#include <iostream>
#include <algorithm>
#include <map>
using namespace std;
#define clr(x) memset(x , 0 , sizeof(x))
#define set(x) memset(x , -1 , sizeof(x))
typedef long long LL ; const int CHAR_SIZE = ;
const int MAX_SIZE = ;
const int M = ; struct AC_Machine{
int ch[MAX_SIZE][CHAR_SIZE] , val[MAX_SIZE] , fail[MAX_SIZE] , que[MAX_SIZE];
int sz;
bool vis[MAX_SIZE];
void init(){
sz = ;
clr(ch[]) , clr(val) , clr(vis);
} int insert(string s){
int n = s.length();
int u= ;
for(int i= ; i<n ; i++){
int c = s[i]-'a';
if(!ch[u][c]){
clr(ch[sz]) , val[sz]=;
ch[u][c] = sz++;
}
u = ch[u][c];
val[u]++;
}
return u;
} void get_fail(){
queue<int> Q;
fail[] = ;
int cnt = ;
for(int c= ; c<CHAR_SIZE ; c++){
int u = ch[][c];
if(u){Q.push(u);fail[u]=,que[cnt++]=u;}
}
while(!Q.empty()){
int r = Q.front();
Q.pop();
for(int c= ; c<CHAR_SIZE ; c++){
int u = ch[r][c];
if(!u){ch[r][c] = ch[fail[r]][c]; continue;}
fail[u] = ch[fail[r]][c];
Q.push(u);
que[cnt++]=u;
}
}
}
void updateVal(){
for(int i=sz- ; i> ; i--)
val[fail[que[i]]]+=val[que[i]];
}
}ac;
int n , pos[];
string s[]; int main()
{
// freopen("a.in" , "r" , stdin);
// freopen("out.txt" , "w" , stdout);
scanf("%d" , &n);
ac.init();
for(int i= ; i<n ; i++){
cin>>s[i];
pos[i] = ac.insert(s[i]);
}
ac.get_fail();
ac.updateVal();
for(int i= ; i<n ; i++)
printf("%d\n" , ac.val[pos[i]]);
return ;
}

bzoj 3172 单词 ac自动机|后缀数组的更多相关文章

  1. 字符串的模板 Manacher kmp ac自动机 后缀数组 后缀自动机

    为何scanf("%s", str)不需要&运算 经常忘掉的字符串知识点,最好不加&,不加&最标准,指针如果像scanf里一样加&是错的,大概是未定 ...

  2. Trie树&kmp&AC自动机&后缀数组&Manacher

    Trie 计数+Trie,读清题意很重要 https://vjudge.net/problem/UVALive-5913 kmp AC自动机 模板:https://vjudge.net/problem ...

  3. (17/34)AC自动机/后缀数组/后缀自动机(施工中)

    快补题别再摸鱼了(17/34) 1.AC自动机 #define maxnode 1000010 #define maxsize 26 struct ahocT{ int ch[maxnode][max ...

  4. BZOJ 3172: [Tjoi2013]单词 [AC自动机 Fail树]

    3172: [Tjoi2013]单词 Time Limit: 10 Sec  Memory Limit: 512 MBSubmit: 3198  Solved: 1532[Submit][Status ...

  5. BZOJ 3172 单词(ac自动机)

    题目链接:http://61.187.179.132/JudgeOnline/problem.php?id=3172 题意:给出n个单词.输出每个单词在所有单词中一共出现多少次? 思路:首先将所有单词 ...

  6. bzoj 3172: [Tjoi2013]单词 AC自动机

    3172: [Tjoi2013]单词 Time Limit: 20 Sec  Memory Limit: 256 MB 题目连接 http://www.lydsy.com/JudgeOnline/pr ...

  7. 【BZOJ 3172】[Tjoi2013]单词 AC自动机

    关于AC自动机:一个在kmp与Trie的基础上建立的数据结构,关键在于Trie树结构与fail指针,他们各有各的应用.在AC自动机里最典型的就是多串匹配,原本效率为O(n*l+n*l+m*l),(n是 ...

  8. BZOJ 2905: 背单词 AC自动机+fail树+dfs序+线段树

    Description 给定一张包含N个单词的表,每个单词有个价值W.要求从中选出一个子序列使得其中的每个单词是后一个单词的子串,最大化子序列中W的和. Input 第一行一个整数TEST,表示数据组 ...

  9. bzoj 3796: Mushroom追妹纸 AC自动机+后缀自动机+dp

    题目大意: 给定三个字符串s1,s2,s3,求一个字符串w满足: w是s1的子串 w是s2的子串 s3不是w的子串 w的长度应尽可能大 题解: 首先我们可以用AC自动机找出s3在s1,s2中出现的位置 ...

随机推荐

  1. 浏览器禁止js打开新窗口

    在项目中,有个需求是需要ajax获取新地址,然后去打开该页面地址,这样会被浏览器拦截,可以采取以下方式:1.再ajax请求先前,先创建一个新窗口 var newTab = window.open('' ...

  2. DSO的记录模式Record Mode字段测试

    声明:原创作品,转载时请注明文章来自SAP师太技术博客( 博/客/园www.cnblogs.com):www.cnblogs.com/jiangzhengjun,并以超链接形式标明文章原始出处,否则将 ...

  3. eclipse加载maven工程提示pom.xml无法解析org.apache.maven.plugins:maven-resources-plugin:2.4.3解决方案

    pom文件提示信息: Failure to transfer org.apache.maven.plugins:maven-resources-plugin:pom:2.4.3 from http:/ ...

  4. JavaScript 的 defer 与 async

    当解析器遇到 script 标签时,文档的解析将停止,并立即下载并执行脚本,脚本执行完毕后将继续解析文档.但是我们可以将脚本标记为 defer,这样就不会停止文档解析,等到文档解析完成才执行脚本,也可 ...

  5. laravel old

    最近做一个laravel框架下的一个网页.遇到了old 无法点击选中的问题,捉摸好久,原来,laravel下的old 是基于seesion下的. 如果想用old必须要在session有的情况下.

  6. Greenlets间如何实现互相通信?

    Greenlets互相通信之Event 1.为什么引入Event: 2.Event是什么: 3.编程实例. 为什么引入Event 1.windows中有Events,作为线程间同步的方法: 2.Gev ...

  7. java:StringBuffer字符处理对象

    1.添加字符 public class StringBufferDemo { public static void main(String args[]) { StringBuffer sbf = n ...

  8. alibaba fastjson List<Map<String, String>>2Str

    import java.util.ArrayList;import java.util.HashMap;import java.util.List;import java.util.Map; impo ...

  9. flask配置qq邮箱发送邮件

    1.第三方登录qq邮箱不是使用邮箱密码,而是使用独立的授权码: 2.开始在python程序中使用os.environ.get()一直无法获取到环境变量,即使是用source命令重新加载配置文件后使用e ...

  10. 关于codeblock中一些常用的快捷键(搬运)

    关于codeblock中一些常用的快捷键(搬运) codeblock作为一个常用的C/C++编译器,是我最常用的一款编译器,但也因为常用,所以有时为了更加快速的操作难免会用到一些快捷键,但是因为我本身 ...