病毒侵袭

HDOJ-2896

  • 主要使用AC自动机解决,其次在query函数中改变一下,用来记录每个模板串出现的次数,还有insert函数中记录模板串的编号
  • 需要注意最好使用结构体,而且不能一次性使用memset否则会超时
  • 上次没有AC出现了output limit exceed问题,后来发现是我的num数组开的太小了,只开了505,实际上需要N的空间。
  • 还有一个问题就是我以前提交的时候很容易就MLE,内存超限,直到我把AC自动机封存到一个结构体中,而且并不是一开始就使用memsettrie树上的结点,而是在建树的时候建一个结点就memset一个结点,这样节省空间。
//AC自动机,复杂度为O(|t|+m),t表示文本串的长度,m表示模板串的个数
#include<iostream>
#include<cstring>
#include<string>
#include<cstdio>
#include<algorithm>
#include<queue>
#include<set>
using namespace std;
const int N=56600;
int n;
string s[502];
set<int>::iterator it;
string t;
struct ACM{
int tree[N][128];//trie树上的结点,tree[i][j]表示i结点后面加一条j的边所对应的的结点
int total;//总结点
int num[N];//num[i]表示结点i上对应的模板串的编号
int fail[N];//失配指针,fail[i]指向所有模板串的前缀中匹配当前状态的最长后缀,指向的是最长后缀(和当前状态的后缀是匹配的,即相同,不过要最长)
int val[N];//val[j]表示结点j所对应的模板串在文本串中出现的次数
set<int> se;
queue<int> q;
void init(){
total=0;
val[0]=fail[0]=num[0]=0;
memset(tree[0],0,sizeof(tree[0]));
}
int idx(char c){//用来求字符c对应的编号(0-25)
return c-0;
}
void insert(string s,int id){//类似于后缀树的插入一个模板串.id表示所有模板串中该模板串的编号
int u=0;
for(int i=0;i<s.length();i++){
if(!tree[u][idx(s[i])])
tree[u][idx(s[i])]=++total;
memset(tree[total],0,sizeof(0));
u=tree[u][idx(s[i])];
}
num[u]=id;
}
void build(){//建AC自动机以及fail数组
for(int i=0;i<128;i++){
if(tree[0][i]){
q.push(tree[0][i]);
fail[tree[0][i]]=0;
}
}
while(!q.empty()){
int u=q.front();
q.pop();
for(int i=0;i<128;i++){
if(tree[u][i]){//如果结点u连的边为i对应的结点存在,则将这个存在的结点的fail指针指向父节点失配指针指向的结点的连的边为i所对应的的结点
fail[tree[u][i]]=tree[fail[u]][i];
q.push(tree[u][i]);
}else{//类似于状态压缩,不至于每次fail指针跳转很多次,只需每次跳转一次,相当于构建了图
tree[u][i]=tree[fail[u]][i];
}
}
}
}
void query(string t){//s为要查找的文本串
se.clear();
int u=0;
int res=0;//记录答案,所有的模板串共出现了多少次
for(int i=0;i<t.length();i++){
u=tree[u][idx(t[i])];
for(int j=u;j>0;){
val[j]++;
j=fail[j];
}
}
for(int i=0;i<=total;i++){//注意:这里是i<=total ,而不是<total,否则报错
if(num[i]){//如果i结点对应着一个模板串,该模板串编号为num[i].
if(val[i]>0){
se.insert(num[i]);//模板串对应的编号插入set中
val[i]=0;
}
}
}
//return res;
}
};
ACM ac;
int main(){
ios::sync_with_stdio(false);
cin.tie(0);
cin>>n;
ac.init();
for(int i=1;i<=n;i++){
cin>>s[i];
ac.insert(s[i],i);
}
ac.build();
int m;
cin>>m;
int ans=0;
for(int i=1;i<=m;i++){
cin>>t;
//memset(val,0,sizeof(val));
ac.query(t);
int size=ac.se.size();
if(size>0){
//cout<<se.size()<<endl;
ans++;
cout<<"web "<<i<<":";
int cnt=0;
for(it=ac.se.begin();it!=ac.se.end();it++){
cout<<" "<<*it;
}
cout<<endl;
}
}
cout<<"total: "<<ans<<endl;
//system("pause");
return 0;
}

HDOJ-2896(AC自动机+文本串中出现了哪几个模板串)的更多相关文章

  1. hdu 2896 AC自动机

    // hdu 2896 AC自动机 // // 题目大意: // // 给你n个短串,然后给你q串长字符串,要求每个长字符串中 // 是否出现短串,出现的短串各是什么 // // 解题思路: // / ...

  2. poj3080Blue Jeans(在m个串中找到这m个串的 最长连续公共子序列)

    Description The Genographic Project is a research partnership between IBM and The National Geographi ...

  3. HDU 2896 (AC自动机模板题)

    题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=2896 题目大意:多个模式串.多个匹配串.其中串的字符范围是(0~127).问匹配串中含有哪几个模式串 ...

  4. hdu 2896 AC自动机模版题

    题意:输出出现模式串的id,还是用end记录id就可以了. 本题有个关键点:“以上字符串中字符都是ASCII码可见字符(不包括回车).”  -----也就说AC自动机的Trie树需要128个单词分支. ...

  5. POJ 2896 AC自动机 or 暴力

    DESCRIPTION :大意是说.给你n个代表病毒的字符串.m个表示网站的字符串.让你计算有多少个网站被病毒感染了.被那些病毒感染了. 刚开始就想暴力.然而,忽略了条件:每个网站最多有三个病毒.于是 ...

  6. HDU 2087 剪花布条(模式串在主串中出现的次数主串中子串不可重叠)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2087 题意:求模式串在主串中出现的次数,与模式串匹配的子串之间不可重叠. 思路:用kmp算法解决,在匹 ...

  7. HDU 2896 AC自动机 裸题

    中文题题意不再赘述 注意字符范围是可见字符,从32开始到95 char c - 32 #include <stdio.h> #include <string.h> #inclu ...

  8. 【AC自动机】HDU中模板题

    [HDU2222] 最纯粹的裸题,错误点详见注释. #include<iostream> #include<cstdio> #include<cstring> #i ...

  9. 字符串——AC自动机

    目录 一.前言 二.思路 三.代码 四.参考资料 一.前言 以前一直没学AC自动机,主要是被名字吓到了,自动AC,这么强的名字肯定很难,学了后才发现,其实不难. AC自动机并不是Acept autom ...

随机推荐

  1. poj 1696 极角排序(解题报告)

    #include<iostream> #include<cmath> #include<algorithm> using namespace std; double ...

  2. 【noi 2.6_162】Post Office(DP)

    这题和"山区建小学"除了输入不同,其他都一样.(解析可见我的上一篇随笔) 但是,这次我对dis[][]加了一个优化,画一下图就可明白. 1 #include<cstdio&g ...

  3. HDU-6290 奢侈的旅行 (Dijkstra+堆优化)

    高玩小Q不仅喜欢玩寻宝游戏,还喜欢一款升级养成类游戏.在这个游戏的世界地图中一共有nn个城镇,编号依次为11到nn.这些城镇之间有mm条单向道路,第ii 条单项道路包含四个参数ui,vi,ai,biu ...

  4. Codeforces Round #646 (Div. 2) C. Game On Leaves (贪心,博弈)

    题意:给你一棵树,每次可以去掉叶节点的一条边,Ayush先开始,每回合轮流来,问谁可以第一个把\(x\)点去掉. 题解:首先如果\(x\)的入度为\(1\),就可以直接拿掉,还需要特判一下入度为\(0 ...

  5. 用了很多年Dubbo,连Dubbo线程池监控都不知道,觉得自己很厉害?

    前言 micrometer中自带了很多其他框架的指标信息,可以很方便的通过prometheus进行采集和监控,常用的有JVM的信息,Http请求的信息,Tomcat线程的信息等. 对于一些比较活跃的框 ...

  6. LOJ6285 数列分块入门9(分块 区间众数)题解

    题意:给出区间内的最小众数 思路:分块,离散化每个数,开vector记录每个数p出现的位置,这样就能二分出L,R以内p的个数了.众数有一个性质,用mode(a)表示集合a的众数,那么mode(a∪b) ...

  7. 洛谷p1886滑动窗口最大最小值 双单调队列

    #include <iostream> #include <cstdio> using namespace std; int n,k,a[1000007],q1[2000007 ...

  8. 如何使用 Python 编写后端 API 接口

    如何使用 Python 编写后端 API 接口 get API Python3 # coding:utf-8 import json # ModuleNotFoundError: No module ...

  9. webpack remove console.log

    webpack remove console.log https://stackoverflow.com/questions/41040266/remove-console-logs-with-web ...

  10. 2015 - 2020 最新 Linux 命令大全

    # 2015 - 2020 最新 Linux 命令大全 ## VIM 命令模式(Command mode):vi 插入模式(Insert mode):i底线命令模式(Last line mode):e ...