病毒的侵扰和再侵扰两道AC自动机的应用
HDU2896 病毒的侵扰
http://vjudge.net/problem/viewProblem.action?id=16404
题目大意:
记录每个病毒的编号,并给出一些网站的源码,分别输出网站及其对应编号中所含病毒的编号,没有就不输出
最后输出有病毒网站的个数
这道题需要注意的是这个所有ASCII码均会用到,所以我之前傻傻地写str[i]-'a'还不知为什么会错简直苦逼~~
这里直接用ch[now][str[i]]找到对应位置即可
因为要记录编号,为了防止重复访问,我对query中进行了一个visit[]数组访问进行判断的操作
query函数如下:
void query(char *str){
int len=strlen(str);
int now=root,ret=;
for(int i=;i<len;i++){
now=ch[now][str[i]];
int k=now;
while(k!=root&&(!visit[k]&&val[k])){//这是要循环到找到fail值为root的时候或者找到匹配的字符串的时候,否则一直向前找fail值,
if(!visit[k])sum++,ans[ret++]=val[k],visit[k]=;
k=last[k];
}
}
}
用ans[]记录所有编号,sum记录病毒个数,那么就可以在main函数进行sort(ans,ans+sum)进行排序好就可以输出了
总代码如下:
#include <cstdio>
#include <cstring>
#include <queue>
#include <algorithm>
using namespace std;
#define N 500*201
char str[];
int ans[],visit[N],sum;
struct AC{
int ch[N][],fail[N],val[N],last[N],tmp,root,cnt;
int newnode(){
val[tmp]=;
memset(ch[tmp],,sizeof(ch[tmp]));
return tmp++;
}
void init(){
tmp=,cnt=;
root=newnode();
}
void add(char *s){
int len=strlen(s);
int now=root;
for(int i=;i<len;i++){
int &k=ch[now][s[i]];
if(!k) k=newnode();
now=k;
}
cnt++;
val[now]=cnt;
}
void get_fail(){
fail[root]=root;
queue<int> q;
for(int i=;i<;i++){
int v=ch[root][i];
if(v)
fail[v]=last[v]=,q.push(v);
}
while(!q.empty()){
int now=q.front();
q.pop();
for(int i=;i<;i++){
int v=ch[now][i];
if(!v) ch[now][i]=ch[fail[now]][i];
else{
fail[v]=ch[fail[now]][i];
last[v]=val[fail[v]]?fail[v]:last[fail[v]];
q.push(v);
}
}
}
}
void query(char *str){
int len=strlen(str);
int now=root,ret=;
for(int i=;i<len;i++){
now=ch[now][str[i]];
int k=now;
while(k!=root&&(!visit[k]&&val[k])){//这是要循环到找到fail值为root的时候或者找到匹配的字符串的时候,否则一直向前找fail值,
if(!visit[k])sum++,ans[ret++]=val[k],visit[k]=;
k=last[k];
}
}
}
}ac;
int main()
{
int n,m;
while(scanf("%d",&n)!=EOF){
memset(ans,,sizeof(ans));
ac.init();
for(int i=;i<n;i++){
scanf("%s",str);
ac.add(str);
}
ac.get_fail();
scanf("%d",&m);
int c=;
for(int i=;i<=m;i++){
sum=;
scanf("%s",str);
memset(visit,,sizeof(visit));
ac.query(str);
sort(ans,ans+sum);
if(sum>){
printf("web %d:",i);
for(int j=;j<sum;j++) printf(" %d",ans[j]);
printf("\n");
c++;
}
}
printf("total: %d\n",c);
}
return ;
}
HDU 3065病毒再侵扰
http://vjudge.net/problem/viewProblem.action?id=16405
给一堆带序号的病毒,再给一个网站源码,问这个网站有哪些病毒,分别有几个,输出病毒码和其对应的个数
这里的query主串中因为会重复模式串,所以不能将val[]数组进行清零,要让他每次都能访问到
void query(char *str){
int len=strlen(str);
int now=root;
for(int i=;i<len;i++){
now=ch[now][str[i]];
int k=now;
while(k!=root){//这是要循环到找到fail值为root的时候或者找到匹配的字符串的时候,否则一直向前找fail值,
if(val[k]>) ans[val[k]]++;
k=last[k];
}
}
}
这道题和上一道字符串有所区别,这里病毒码只有26个大写字母,主串可以是128个ASCII码的任何字符
当然直接在AC结构体中定义ch[N][128]也并未超内存
这是我最开始写的代码:
Memory: 16756 KB | Time: 296 MS | |
Language: G++ |
Result: Accepted |
#include <cstdio>
#include <cstring>
#include <queue>
#include <iostream>
#include <string>
using namespace std;
#define N 1000*52
char str[];
int ans[];
struct AC{
int ch[N][],fail[N],val[N],last[N],tmp,root;
int newnode(){
val[tmp]=;
memset(ch[tmp],,sizeof(ch[tmp]));
return tmp++;
}
void init(){
tmp=;
root=newnode();
}
void add(string s,int cnt){
int len=s.length();
int now=root;
for(int i=;i<len;i++){
int &k=ch[now][s.at(i)];
if(!k) k=newnode();
now=k;
}
val[now]=cnt;
}
void get_fail(){
fail[root]=root;
queue<int> q;
for(int i=;i<;i++){
int v=ch[root][i];
if(v)
fail[v]=last[v]=,q.push(v);
}
while(!q.empty()){
int now=q.front();
q.pop();
for(int i=;i<;i++){
int v=ch[now][i];
if(!v) ch[now][i]=ch[fail[now]][i];
else{
fail[v]=ch[fail[now]][i];
last[v]=val[fail[v]]?fail[v]:last[fail[v]];
q.push(v);
}
}
}
}
void query(char *str){
int len=strlen(str);
int now=root;
for(int i=;i<len;i++){
now=ch[now][str[i]];
int k=now;
while(k!=root){//这是要循环到找到fail值为root的时候或者找到匹配的字符串的时候,否则一直向前找fail值,
if(val[k]>) ans[val[k]]++;
k=last[k];
}
}
}
}ac;
int main()
{
int n;
string s[];
while(scanf("%d",&n)!=EOF){
memset(ans,,sizeof(ans));
ac.init();
for(int i=;i<n;i++){
cin>>s[i+];
ac.add(s[i+],i+);
}
ac.get_fail();
scanf("%s",str);
ac.query(str);
for(int i=;i<=;i++){
if(ans[i]>) cout<<s[i]<<": "<<ans[i]<<endl;
}
}
return ;
}
但是我们定义一个ch[N][26]的数组却可以减少更多的内存占用,那么我们每次找位置都是用now=ch[now][str[i]-'A']来进行操作
在query中面对不在A~Z范围内的数,我们就利用一个if判断条件来做
if(str[i]<'A'||str[i]>'Z') now=root;//因为不在A~Z范围内的数是不存在有字母能跟它进行匹配的,所以直接将指针移回根节点重新进行判断
else{
}
Memory: 5584 KB | Time: 187 MS | |
Language: G++ | Result: Accepted |
#include <cstdio>
#include <cstring>
#include <queue>
#include <iostream>
#include <string>
using namespace std;
#define N 1000*52
char str[];
int ans[];
struct AC{
int ch[N][],fail[N],val[N],last[N],tmp,root;
int newnode(){
val[tmp]=;
memset(ch[tmp],,sizeof(ch[tmp]));
return tmp++;
}
void init(){
tmp=;
root=newnode();
}
void add(string s,int cnt){
int len=s.length();
int now=root;
for(int i=;i<len;i++){
int &k=ch[now][s.at(i)-'A'];
if(!k) k=newnode();
now=k;
}
val[now]=cnt;
}
void get_fail(){
fail[root]=root;
queue<int> q;
for(int i=;i<;i++){
int v=ch[root][i];
if(v)
fail[v]=last[v]=,q.push(v);
}
while(!q.empty()){
int now=q.front();
q.pop();
for(int i=;i<;i++){
int v=ch[now][i];
if(!v) ch[now][i]=ch[fail[now]][i];
else{
fail[v]=ch[fail[now]][i];
last[v]=val[fail[v]]?fail[v]:last[fail[v]];
q.push(v);
}
}
}
}
void query(char *str){
int len=strlen(str);
int now=root;
for(int i=;i<len;i++){
if(str[i]>'Z'||str[i]<'A') now=root;
else{
now=ch[now][str[i]-'A'];
int k=now;
while(k!=root){//这是要循环到找到fail值为root的时候或者找到匹配的字符串的时候,否则一直向前找fail值,
if(val[k]>) ans[val[k]]++;
k=last[k];
}
}
}
}
}ac;
int main()
{
int n;
string s[];
while(scanf("%d",&n)!=EOF){
memset(ans,,sizeof(ans));
ac.init();
for(int i=;i<n;i++){
cin>>s[i+];
ac.add(s[i+],i+);
}
ac.get_fail();
scanf("%s",str);
ac.query(str);
for(int i=;i<=;i++){
if(ans[i]>) cout<<s[i]<<": "<<ans[i]<<endl;
}
}
return ;
}
病毒的侵扰和再侵扰两道AC自动机的应用的更多相关文章
- 一道cf水题再加两道紫薯题的感悟
. 遇到一个很大的数除以另一个数时,可以尝试把这个很大的数进行,素数因子分解. . 遇到多个数的乘积与另一个数的除法时,求是否能整除,可以先求每一个数与分母的最大公约数,最后若分母数字为1,则证明可整 ...
- [hdu3065]病毒侵袭持续中(AC自动机)
题意:给出多种病毒的号码和特征码,计算在某串中各病毒匹配的次数. 解题关键:AC自动机模板题,多组输入坑人. #include<bits/stdc++.h> using namespace ...
- ACM/ICPC 之 两道dijkstra练习题(ZOJ1053(POJ1122)-ZOJ1053)
两道较为典型的单源最短路径问题,采用dijkstra解法 本来是四道练习题,后来发现后面两道用dijkstra来解的话总觉得有点冗余了,因此暂且分成三篇博客(本篇以及后两篇). ZOJ1053(POJ ...
- 两道面试题,带你解析Java类加载机制
文章首发于[博客园-陈树义],点击跳转到原文<两道面试题,带你解析Java类加载机制> 在许多Java面试中,我们经常会看到关于Java类加载机制的考察,例如下面这道题: class Gr ...
- 【转】两道面试题,带你解析Java类加载机制(类初始化方法 和 对象初始化方法)
本文转自 https://www.cnblogs.com/chanshuyi/p/the_java_class_load_mechamism.html 关键语句 我们只知道有一个构造方法,但实际上Ja ...
- 『ACM C++』Virtual Judge | 两道基础题 - The Architect Omar && Malek and Summer Semester
这几天一直在宿舍跑PY模型,学校的ACM寒假集训我也没去成,来学校的时候已经18号了,突然加进去也就上一天然后排位赛了,没学什么就去打怕是要被虐成渣,今天开学前一天,看到最后有一场大的排位赛,就上去试 ...
- (转)关于inode和block的两道企业面试题
关于inode和block的两道企业面试题 原文:http://www.tk4479.net/xiaolong361/article/details/52373374 一.一个100M的磁盘分区,分别 ...
- 你所不知道的库存超限做法 服务器一般达到多少qps比较好[转] JAVA格物致知基础篇:你所不知道的返回码 深入了解EntityFramework Core 2.1延迟加载(Lazy Loading) EntityFramework 6.x和EntityFramework Core关系映射中导航属性必须是public? 藏在正则表达式里的陷阱 两道面试题,带你解析Java类加载机制
你所不知道的库存超限做法 在互联网企业中,限购的做法,多种多样,有的别出心裁,有的因循守旧,但是种种做法皆想达到的目的,无外乎几种,商品卖的完,系统抗的住,库存不超限.虽然短短数语,却有着说不完,道不 ...
- 穷举(四):POJ上的两道穷举例题POJ 1411和POJ 1753
下面给出两道POJ上的问题,看如何用穷举法解决. [例9]Calling Extraterrestrial Intelligence Again(POJ 1411) Description A mes ...
随机推荐
- RAID基础
磁盘类型 类型 IDE Integrated Drive Electronics SATA Srial ATA SCSI Small Computer System Interface FC Fibe ...
- python_11(网络编程)
第1章 ucp协议 1.1 特性 1.2 缺陷 1.3 UDP协议实时通信 第2章 socket的更多方法 2.1 面向锁的套接字方法 2.1.1 blocking设置非阻塞 2.1.2 Blocki ...
- FFmpegUtil
这几天没事研究音频玩 比如 X配音app的配音功能 录一段 pcm或者wav格式的文件 替换mp4指定位置的音频刚开始卡在 pcm混合以及pcm指定位置插入.思路 一段段的视频进行切割 用到MP4Co ...
- 如何从GAC中拷贝文件出来 C:\Windows\assembly
方法一:命令行拷贝. 开始--运行--cmd--"cd C:\WINDOWS\assembly".一般自己开发的dll都在GAC_MSIL这个文件夹下面,按照我如下的截图就可以拷贝 ...
- JavaScript——数组的indexOf()方法在IE8中的兼容性问题
昨天在工作中遇到一个问题:数组的indexOf()方法在IE8中无效. 如以下代码在IE8中报错“对象不支持“indexOf”属性或方法”: var arr = [1,2,3]; var index ...
- 离开APM的弹性云还是真弹性吗
准确来说应该叫脱离业务的弹性云或者容器都是伪弹性.之所以标题中有APM一是因为它近来热门,二是因为它在我将要说的这个事情上起到关键性的作用. 不管是亚马逊的弹性云.容器方案或者国内众多云厂商在自动伸缩 ...
- String.format()【示例详解】
String.format()[示例详解] 整理者:Vashon 前言: String.format 作为文本处理工具,为我们提供强大而丰富的字符串格式化功能,为了不止步于简单调用 String.fo ...
- ZGC,一个超乎想象的垃圾收集器
Z Garbage Collector,即ZGC,是一个可伸缩的.低延迟的垃圾收集器,主要为了满足如下目标进行设计: 停顿时间不会超过10ms 停顿时间不会随着堆的增大而增大(不管多大的堆都能保持在1 ...
- HashMap和HashTable的理解与区别
Hashtable是java一开始发布时就提供的键值映射的数据结构,而HashMap产生于JDK1.2.虽然Hashtable比HashMap出现的早一些,但是现在Hashtable基本上已经被弃用了 ...
- 暑假集训 || 概率DP
Codeforces 148D 考虑状态转移..https://www.cnblogs.com/kuangbin/archive/2012/10/04/2711184.html题意:原来袋子里有w只白 ...