(一下只供自己复习用,目的是对比这几个题,所以写得不详细。需要细节的可以参考其他博主)

【BZOJ3172:单词】

题目:

某人读论文,一篇论文是由许多(N)单词组成。但他发现一个单词会在论文中出现很多次,现在想知道每个单词分别在论文中出现多少次。N<=200,总单词长度不超过10^6。

思路:

简单题,建立AC自动机,插入的时候每个位置都++,代表以当前位置为后缀的字符串的个数,用于fail转移时累加。然后build得到fail指针;最后从叶子向根累加。

#include<bits/stdc++.h>
using namespace std;
const int maxn=;
char c[maxn]; int ans[maxn],pos[],N;
struct Trie
{
int ch[maxn][],cnt,times,fail[maxn],q[maxn],head,tail;
Trie(){ cnt=times=head=tail=; }
int insert(){
int Now=,L=strlen(c+);
for(int i=;i<=L;i++){
if(!ch[Now][c[i]-'a']) ch[Now][c[i]-'a']=++cnt;
Now=ch[Now][c[i]-'a'];
ans[Now]++;
}
return Now;
}
void build()
{
for(int i=;i<;i++)
if(ch[][i]) q[++head]=ch[][i];
while(tail<head){
int Now=q[++tail];
for(int i=;i<;i++){
if(ch[Now][i]){
fail[ch[Now][i]]=ch[fail[Now]][i];
q[++head]=ch[Now][i];
}
else ch[Now][i]=ch[fail[Now]][i];
}
}
for(int i=tail;i>=;i--) ans[fail[q[i]]]+=ans[q[i]];
}
}T;
int main()
{
scanf("%d",&N);
for(int i=;i<=N;i++){
scanf("%s",c+);
pos[i]=T.insert();
}
T.build();
for(int i=;i<=N;i++) printf("%d\n",ans[pos[i]]);
return ;
}

【BZOJ2434阿狸的打字机】:

题目:

给定N个字符串。现在又Q个问题,每次问题给出(X,Y),求第X个字符串在第Y个字符串里出现的次数。 1<=N<=10e5;1<=M<=10e5;输入总长<=10e5

思路:

因为上一题是单次讯问,而且是整体求,所以一次拓扑倒序累加即可,但是此题是多次询问,而且是针对Trie树上代表的两个字符串X和Y之间的包含次数,不能整体法。其实问题是 “Y有多少个节点顺着fail可以走到X节点”; 正解: 1,先建立AC自动机;2,得到fail树;3,对fail树进行DFS得到DFS序;4,在Trie树上dfs求解。

       下面这一段转自huzecong (便于理解,自己加了一点东西) :那么我们可以得到一个离线算法:对fail树遍历一遍,得到一个DFS序(得到fail树每个节点的子树);再维护一个树状数组,对原Trie树进行dfs遍历,每访问一个节点,就修改树状数组,对树状数组中该节点的DFS序起点的位置加上1。每往回走一步,就减去1(模拟一下发现dfs到Y点时,在树状数组里的东西来自于root、Y1、Y2...Y,是一条链;即Y的每一个节点都考虑到是否可以沿fail指针走到X)。如果访问到了一个Y字串的末尾节点,枚举询问中每个Y串对应的X串,查询树状数组中X串末尾节点从DFS序中的起始位置到结束位置的和,并记录答案。这样,我们就得到了一个时间复杂度为O(N+MlogN)的优美的算法。因为N和M都不超过105,所以这个算法是可行的。

#include<bits/stdc++.h>
using namespace std;
const int maxn=;
char c[maxn]; int pos[maxn],num,ans[maxn]; //记录输入字符串位置
vector<int>G[maxn]; //用于建fail树
int Laxt[maxn],Next[maxn],To[maxn],id[maxn],tot; //N个问题
void add(int u,int v,int iid) //加问题
{
Next[++tot]=Laxt[u];
Laxt[u]=tot;
To[tot]=v;
id[tot]=iid;
}
struct Trie
{
int cnt,ch[maxn][],fa[maxn],fail[maxn],q[maxn],head,tail;//建立AC自动机,fail树。
int ind[maxn],outd[maxn],times; //对Fail树DFS序部分
int sum[maxn<<]; //对Trie树dfs维护的树状数组部分
Trie(){ cnt=times=head=tail=; }
void insert(){
int Now=,L=strlen(c+);
for(int i=;i<=L;i++){
if(c[i]=='B') Now=fa[Now];
else if(c[i]=='P') pos[++num]=Now;
else {
if(!ch[Now][c[i]-'a']){
ch[Now][c[i]-'a']=++cnt;
fa[cnt]=Now;
}
Now=ch[Now][c[i]-'a'];
}
}
}
void build()
{
for(int i=;i<;i++)
if(ch[][i]){
q[++head]=ch[][i];
G[].push_back(ch[][i]);
}
while(tail<head){
int Now=q[++tail];
for(int i=;i<;i++){
if(ch[Now][i]){
fail[ch[Now][i]]=ch[fail[Now]][i];
G[fail[ch[Now][i]]].push_back(ch[Now][i]);
q[++head]=ch[Now][i];
}
else ch[Now][i]=ch[fail[Now]][i];
}
}
}
void DFS(int Now)
{
ind[Now]=++times;
int L=G[Now].size();
for(int i=;i<L;i++) DFS(G[Now][i]);
outd[Now]=++times;
}
void add(int x,int val){ while(x<=times) { sum[x]+=val; x+=(-x)&x;}}
int query(int x){ int res=; while(x){ res+=sum[x]; x-=(-x)&x;} return res;}
void dfs()
{
int Now=,L=strlen(c+);
for(int i=;i<=L;i++){
if(c[i]=='B') add(ind[Now],-) ,Now=fa[Now];
else if(c[i]=='P'){
for(int j=Laxt[Now];j;j=Next[j]){
int v=To[j];
ans[id[j]]=query(outd[v])-query(ind[v]-);
}
}
else Now=ch[Now][c[i]-'a'],add(ind[Now],);
}
}
}T;
int main()
{
scanf("%s",c+);
T.insert(); T.build();
int N,u,v; scanf("%d",&N);
for(int i=;i<=N;i++){
scanf("%d%d",&u,&v);
add(pos[v],pos[u],i);
}
T.DFS();
T.dfs(); //直接搜索是错的,需要从输入的字符串入手。因为ac自动机ch[]数组的关系是改变了的
for(int i=;i<=N;i++) printf("%d\n",ans[i]);
return ;
}
 
 
【BZOJ3881】
  题意:
         Bob有个字符串集合T,一开始为空,现在有两种操作:1,Bob的集合新增加一个字符串str; 2,Alice给出字符串x,问集合T中多少字符串包含x。1e6级别。
 
 

【字符串】BZOJ上面几个AC自动机求最为字串出现次数的题目的更多相关文章

  1. HDU 3065 病毒侵袭持续中(AC自动机(每个模式串出现次数))

    http://acm.hdu.edu.cn/showproblem.php?pid=3065 题意:求每个模式串出现的次数. 思路: 不难,把模板修改一下即可. #include<iostrea ...

  2. bzoj 3881: [Coci2015]Divljak AC自动机

    题目大意: http://www.lydsy.com/JudgeOnline/problem.php?id=3881 题解: 这道题我想出了三种做法,不过只有最后一种能过. 第一种: 首先我们把所有的 ...

  3. 模板—字符串—AC自动机(多模式串,单文本串)

    模板—字符串—AC自动机(多模式串,单文本串) Code: #include <queue> #include <cstdio> #include <cstring> ...

  4. bzoj 1398: 寻找主人 AC自动机+最小表示法

    题目大意: 给定两个序列判断是否循环同构,若循环同构则输出最小表示 题解: 因为没有样例输入输出,一开始没看到要求输出最小表示 Wa一大页. 但不得不说bzoj还是挺高效的: 赞一个 XD.jpg 判 ...

  5. HDU - 2222,HDU - 2896,HDU - 3065,ZOJ - 3430 AC自动机求文本串和模式串信息(模板题)

    最近正在学AC自动机,按照惯例需要刷一套kuangbin的AC自动机专题巩固 在网上看过很多模板,感觉kuangbin大神的模板最为简洁,于是就选择了用kuangbin大神的模板. AC自动机其实就是 ...

  6. HDOJ-2222(AC自动机+求有多少个模板串出现在文本串中)

    Keywords Search HDOJ-2222 本文是AC自动机的模板题,主要是利用自动机求有多少个模板出现在文本串中 由于有多组输入,所以每组开始的时候需要正确的初始化,为了不出错 由于题目的要 ...

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

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

  8. BZOJ 3881: [Coci2015]Divljak [AC自动机 树链的并]

    3881: [Coci2015]Divljak 题意:添加新文本串,询问某个模式串在多少种文本串里出现过 模式串建AC自动机,考虑添加一个文本串,走到的节点记录下来求树链的并 方法是按dfs序排序去重 ...

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

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

随机推荐

  1. 最小费用最大流粗解 poj2516

    最小费用最大流,一般解法如下: 在流量基础上,每条边还有权费用,即单位流量下的所需费用.在最大流量下,求最小费用.解法:在最大流算法基础上,每次按可行流增广改为每次用spfa按最小费用(用单位费用)增 ...

  2. argument to nsmutablearray method addobject cannot be nil 警告

    You cannot add nil to an NSMutableArray, and you will raise an exception if you try to. There's NSNu ...

  3. python 怎么启动一个外部命令程序, 并且不阻塞当前进程

    http://www.myexception.cn/perl-python/1278887.html http://blog.chinaunix.net/uid-25979788-id-3081912 ...

  4. BUPT复试专题—科学计算器(2009)

    题目描述 给你一个不带括号的表达式,这个表达式只包含加.减.乘.除,请求出这个表 达式的最后结果,最后结果一定是整数: 输入 一个数学表达式,只包括数字,数字保证是非负整数,以及五种运算符 " ...

  5. BUPT复试专题—找最小数(2010)

    https://www.nowcoder.com/practice/ba91786c4759403992896d859e87a6cd?tpId=67&tqId=29645&rp=0&a ...

  6. Android studio 导入githubproject

    Blog From:http://blog.csdn.net/onlysnail/article/details/45115093 从github下载两个开源项目: PagerSlidingTabSt ...

  7. [转载]JSONP跨域的原理解析

    JavaScript是一种在Web开发中经常使用的前端动态脚本技术.在JavaScript中,有一个很重要的安全性限制,被称为“Same-Origin Policy”(同源策略).这一策略对于Java ...

  8. cocos2d-x 3.0 touch事件官方解释

    官方解释 http://www.cocos2d-x.org/docs/manual/framework/native/input/event-dispatcher/zh#_1

  9. BEGINNING SHAREPOINT&#174; 2013 DEVELOPMENT 第8章节--配送SP2013Apps 应用程序生命周期

    BEGINNING SHAREPOINT® 2013 DEVELOPMENT 第8章节--配送SP2013Apps 应用程序生命周期         你在商店拥有一个应用程序后.跟踪不论什么人们碰到的 ...

  10. Xammp修改端口

    How can I get XAMPP working on port 80 under Windows 10? By default, Windows 10 starts Microsoft IIS ...