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

【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. codeforces 1051 F

    多源点最短路. 但是有限制,m - n <= 20,边数 - 点数 <= 20, 所以这个图非常的稀疏. 任意提取出一个生成树出来,LCA处理任意两点最短路. 然后再去遍历那些多余出来的点 ...

  2. Codeforces 667C Reberland Linguistics【DFS】

    一道卡题意的题. 题目链接: http://codeforces.com/problemset/problem/667/C 题意: 一个串可以看成一个长度大于4的根,加上其后面的若干个相邻(in a ...

  3. 一个iOS开发者的Flutter“历险记”

    1. 官方简介 Flutter是谷歌的移动UI框架,可以快速在iOS和Android上构建高质量的原生用户界面. 官方介绍: 快速开发: 毫秒级的热重载,修改后,您的应用界面会立即更新.使用丰富的.完 ...

  4. Heavy Transportation(最短路)

    poj 1797 ——Heavy Transportation 思路: 这道题我们可以采用类似于求最短路径的方法,用一种新的“松弛操作”去取代原本的方法. 我们可以记录d[u]为运送货物到点j时最大可 ...

  5. java cocurrent并发包

    1. java.util.concurrent - Java 并发工具包Java 5 添加了一个新的包到 Java 平台,java.util.concurrent 包.这个包包含有一系列能够让 Jav ...

  6. 微信小程序 - 提取字体图标与其优化

    微信小程序,无论是字体图标还是图标,都差不多,只不过是为了以后字体图标修改方便,或者加效果方便而使用它而已! 1. 下载font-awesome http://fontawesome.dashgame ...

  7. mybatis 动态curd

    xml <select id="selectByCondition" parameterType="com.oracle.pojo.Student" re ...

  8. python基础小练习

    def main(): number = int(input("请输入学生的总人数:")) # 输入要录入的学生总数 count = number # 用一个变量来保存这个学生总数 ...

  9. 智能停车O2O 独角兽初现:“ETCP停车”获5000万美金A轮融资

        日前,国内第一智能停车平台"ETCP停车"宣布完毕A轮融资,由源代码资本.SIG.易车网.经纬中国和商企界知名人士联合投资超过5000万美金.同一时候获悉,ETCP作为中国 ...

  10. Linux 及 CentOS系统安装

    VMware与Centos系统安装   今日任务 .Linux发行版的选择 .vmware创建一个虚拟机(centos) .安装配置centos7 .xshell配置连接虚拟机(centos) 选择性 ...