第一道AC自动机题目。

记一下对AC自动机的理解吧:

AC自动机=Trie+KMP。即在Trie上应用KMP思想,实现多Pattern的匹配问题。

复杂度是预处理O(segma len(P)),匹配是O(len(T))。应该也是下界了。

它预处理做了以下事情:

  1、建立所有Pattern的Trie

  2、计算出fail和last数组

匹配时和KMP很像。

我对fail和last的理解:

  对于一棵Trie,上面的一个节点对应一个字符串,该字符串是root到该节点的路径上,边代表的字符连接起来的。

fail[i]是一个指针,它指向一个节点f,使得f代表的字符串是i代表的字符串最长的一个后缀(所以f的深度一定比i小)。

last[i]也是一个指针,它指向一个节点f,使得f代表的字符串是i代表的字符串的一个后缀且该后缀也是一个Pattern。(如果不存在则指向根)。

我们将根节点代表的字符串理解成空串,空串是任何字符串的子串。

对于匹配过程,我们将Text串也想成一个由点和边组成的链,我们从最左边的点开始向右开始匹配。

我们以Text串的位置为阶段进行匹配,如果Trie的当前节点存在一条边,使得它代表的字符串和text串一致,就两边都前进。如果不存在,trie中的节点就不断通过fail向上跳,直到存在边或到达根,如果存在边就同时向下走,否则(即到达根且根也没有对应边),那就trie保持在根,text串到下一节点。

然后每到一个新的trie节点就查看是否匹配到(要用到last数组).


去重的几种方式:

  1、set

  2、sort+unique

  3、mark+vector

各有特点,

set是实时添加和查询,O(nlogn)。

sort+unique是添加完后查询(多用于离散话),也是O(nlogn)(常数比前者小)。

mark+vector,要求范围较小(10^7以内),O(n)

 /**************************************************************
Problem: 2754
User: idy002
Language: C++
Result: Accepted
Time:1320 ms
Memory:13264 kb
****************************************************************/ #include <cstdio>
#include <cctype>
#include <queue>
#include <vector>
#include <set>
#include <map>
#include <algorithm>
#define maxn 100010
using namespace std; typedef vector<int> String; int gint() {
int rt;
char ch, opt;
while( !isdigit(ch=getchar()) ) opt=ch;
rt=ch-'';
while( isdigit(ch=getchar()) ) rt=rt*+ch-'';
return rt;
} int n, m;
int ans[][maxn];
String str[maxn], ss;
bool mark[maxn];
vector<int> in; struct AC {
map<int,int> son[maxn];
set<int> st;
vector<int> stk[maxn];
int fail[maxn], last[maxn], ntot; void insert( int id, String &p ) {
int u=;
for( int i=; i<p.size(); i++ ) {
int c=p[i];
if( !son[u][c] ) son[u][c] = ++ntot;
u=son[u][c];
}
stk[u].push_back(id);
}
void build() {
queue<int> qu;
for( map<int,int>::iterator it=son[].begin(); it!=son[].end(); ++it ) {
int v=it->second;
qu.push(v);
fail[v] = last[v] = ;
}
while(!qu.empty()) {
int u=qu.front();
qu.pop();
for( map<int,int>::iterator it=son[u].begin(); it!=son[u].end(); ++it ) {
int c=it->first;
int v=it->second;
int w=fail[u];
while( w && !son[w][c] ) w=fail[w];
int x=son[w][c];
fail[v] = x;
last[v] = stk[x].size() ? x : last[x];
qu.push(v);
}
}
}
void add( int u ) {
if( !u ) return;
add(last[u]);
for( int t=; t<stk[u].size(); t++ ) {
if( mark[stk[u][t]] ) continue;
mark[stk[u][t]] = true;
in.push_back( stk[u][t] );
}
}
void search( int id, String &T ) {
st.clear();
int u=;
for( int i=; i<T.size(); i++ ) {
while( u && !son[u][T[i]] ) u=fail[u];
u=son[u][T[i]];
if( stk[u].size() ) add(u);
else add(last[u]);
}
ans[][id] += in.size();
for( int t=; t<in.size(); t++ ) {
ans[][in[t]]++;
mark[in[t]]=false;
}
in.clear();
}
}ac; int main() {
n = gint();
m = gint();
for( int i=,z; i<=n; i++ ) {
z = gint();
while(z--) str[i].push_back( gint() );
str[i].push_back(-);
z = gint();
while(z--) str[i].push_back( gint() );
}
for( int i=,z; i<=m; i++ ) {
ss.clear();
z = gint();
while(z--) ss.push_back( gint() );
ac.insert( i, ss );
}
ac.build();
for( int i=; i<=n; i++ )
ac.search( i, str[i] );
for( int i=; i<=m; i++ )
printf( "%d\n", ans[][i] );
for( int i=; i<=n; i++ )
printf( "%d%s", ans[][i], i==n ? "" : " " );
}

bzoj 2754 ac自动机的更多相关文章

  1. bzoj 3172 AC自动机

    初学AC自动机,要先对于每一个模式串求出来trie树,在此基础上构建fail指针,然后在trie树加上失配边构建出整张trie图. AC自动机的原理和KMP差不多,一个节点的fail指针就是指向tri ...

  2. 【无聊放个模板系列】BZOJ 3172 (AC自动机)

    #include<cstdio> #include<cstdlib> #include<cstring> #include<iostream> #inc ...

  3. bzoj 2434 AC自动机+树状数组

    2434: [Noi2011]阿狸的打字机 Time Limit: 10 Sec  Memory Limit: 256 MBSubmit: 3493  Solved: 1909[Submit][Sta ...

  4. bzoj 1030 AC自动机+dp

    代码: //先把给的单词建AC自动机并且转移fail,然后d[i][j]表示构造的文章到第i位时处在字典树的第j个节点的不包含单词的数量,最后用总的数量26^m //-d[m][0~sz]即可.其中不 ...

  5. bzoj 2434 ac自动机

    ac自动机中,如果以trie中的节点为节点,(fail[i],i)为边,可以建立一颗树,该树有如下特点:“节点u是节点v的祖先 当且仅当 u代表的字符串是v代表的字符串的一个后缀”.(u代表的字符串是 ...

  6. bzoj 1030 ac自动机

    比较容易看出来先建立ac自动机,然后在自动机上做DP,设w[0..1][i][j]为当前不包括/包括字典中的字符串,当前在自动机中走到第i个节点,完成的文本的长度为j的方案数,那么比较容易的转移w[i ...

  7. bzoj 2434 AC自动机 + fail指针建树 + 树状数组

    思路:我们先跟着它给定的字符串走把字典树建出来,求出fail指针,我们考虑两个字符串 A和B, 如果想要求B中有多少A的子串,转换一下就是有多少个B的前缀的后缀包含A,这个在AC自动机 的状态图中很容 ...

  8. bzoj 1444 AC自动机 + 矩阵乘法 | 高斯消元

    恶补了一下AC自动机,花了一天时间终于全部搞明白了. 思路:将每个人的串加入AC自动机,在AC自动机生成的状态图上建边,注意单词末尾的节点只能转移到自己概率为1, 然后将矩阵自乘几十次后误差就很小了, ...

  9. BZOJ 3940 AC自动机

    思路: 需要维护一个栈的AC自动机--. 要求出来 最后的栈顶是在自动机上的哪个节点. if(!ac.ch[st[tp-1]][a[i]-'a']) st[tp]=ac.ch[ac.f[st[tp-1 ...

随机推荐

  1. HNU Joke with permutation (深搜dfs)

    题目链接:http://acm.hnu.cn/online/?action=problem&type=show&id=13341&courseid=0 Joke with pe ...

  2. 阿里云一键web环境包

    下载地址:https://files.cnblogs.com/files/wordblog/af3a48ef-3a13-479e-85c9-ead61173126c.zip 先把安装包传到服务器上用w ...

  3. 阿里分布式开源框架DUBBO 入门+ 进阶+ 项目实战视频教程

    史诗级Java/JavaWeb学习资源免费分享 欢迎关注我的微信公众号:"Java面试通关手册"(坚持原创,分享各种Java学习资源,面试题,优质文章,以及企业级Java实战项目回 ...

  4. word2vec原理

    最原始的是NNLM,然后对其改进,有了后面的层次softmax和skip gram 层次softmax:去掉了隐藏层,后面加了huffuman树,concat的映射层也变成了sum skip gram ...

  5. java.lang.IllegalArgumentException: Page directive: invalid value for import

    我的项目原来用的tomcat版本是apache-tomcat-7.0.53,后来为了安全原因将版本升至\apache-tomcat-7.0.57,发现有的jsp页面出现下面的异常: java.lang ...

  6. DBCP object created 日期 by the following code was never closed:

    1.分析 看到标题 DBCP 首先想到的肯定是 数据库连接池哪方面有问题,那么先别着急去解决,不要一股脑就钻进逻辑代码中,然后启用调试就开始一步一步 的分析.我们首先要做的就是想,想想数据库连接池,在 ...

  7. 构建最基础的Spring项目及所需要的jar包

    1.Spring 框架由6个模块组成 上图是spring4的结构图,不同版本结构略有差异,但模块都是相同的. 2.Core Container 核心容器 容器是Spring的核心部分,Core Con ...

  8. 设置或者获取CheckboxList控件的选中值

    1.设置CheckBoxList选中的值 /// <summary> /// 设置CheckBoxList中哪些是选中了的 /// </summary> /// <par ...

  9. 安装deb包解决依赖问题

    在使用 dpkg -i 安装deb包后,会出现依赖关系而不能正常安装软件,这个时候先更新下源然后解决依赖关系后重装即可. sudo apt-get update # 更新 sudo apt-get - ...

  10. 关于node的path模块

    const path=require('path'); //basename('绝对路径','截取的后缀') 返回文件的扩展名 let a=path.basename('C:\\temp\\myfil ...