【BZOJ4327】[JSOI2012] 玄武密码(AC自动机的小应用)
大致题意: 给你一个长度为\(len\)的文本串和\(n\)个模式串,让你求出每一个模式串的前缀与文本串的最大匹配串长度(其中模式串和文本串都只由字符'E','S','W','N'组成)。
\(AC\)自动机
这是一道\(AC\)自动机的简单运用题。
题解
对于每一个模式串,我们可以记录它的每一个前缀在\(Trie\)上所对应的节点的位置。
在用\(AC\)自动机时,对每一个访问过的节点打个标记,如果遇到已经访问过的节点就\(break\)(因为接下来的节点肯定在第一次访问当前节点时被访问过,不需要重复访问)。
最后输出答案时,对于每一个模式串,只要从后往前枚举它的每一个前缀,一旦遇到一个被访问过的,就输出并结束枚举。
代码
#include<bits/stdc++.h>
#define max(x,y) ((x)>(y)?(x):(y))
#define min(x,y) ((x)<(y)?(x):(y))
#define LL long long
#define ull unsigned long long
#define swap(x,y) (x^=y,y^=x,x^=y)
#define tc() (A==B&&(B=(A=ff)+fread(ff,1,100000,stdin),A==B)?EOF:*A++)
#define pc(ch) (pp_<100000?pp[pp_++]=(ch):(fwrite(pp,1,100000,stdout),pp[(pp_=0)++]=(ch)))
#define N 100000
int pp_=0;char ff[100000],*A=ff,*B=ff,pp[100000];
using namespace std;
int n,len,ee=0,rt=1,tot=1,lens[N+5],ans[N+5][100];
string st;
struct Trie
{
int Son[4],Next,Vis;
}node[100*N+5];
queue<int> q;
inline void read(int &x)
{
x=0;static char ch;
while(!isdigit(ch=tc()));
while(x=(x<<3)+(x<<1)+ch-48,isdigit(ch=tc()));
}
inline void write(int x)
{
if(x>9) write(x/10);
pc(x%10+'0');
}
inline void read_string(string &x)
{
x="";static char ch;
while(isspace(ch=tc()));
while(x+=ch,!isspace(ch=tc())) if(!(~ch)) return;
}
inline int GetPos(char x)//由于只有4个字符,我们可以将其压缩
{
return x=='E'?0:(x=='W'?1:(x=='N'?2:3));
}
inline void Insert(int pos,string st)//将编号为pos的模式串st插入字典树中
{
register int i,nxt,x=rt,len=lens[pos];
for(i=0;i<len;++i)
{
if(!node[x].Son[nxt=GetPos(st[i])]) node[x].Son[nxt]=++tot;
ans[pos][i]=x=node[x].Son[nxt];//记录当前模式串每一个前缀最后到达的节点
}
}
inline void GetNext()//求出失配指针
{
register int i,k;q.push(rt);
while(!q.empty())
{
k=q.front(),q.pop();
for(i=0;i<4;++i)
{
if(k^rt)
{
if(!node[k].Son[i]) node[k].Son[i]=node[node[k].Next].Son[i];
else node[node[k].Son[i]].Next=node[node[k].Next].Son[i],q.push(node[k].Son[i]);
}
else
{
if(!node[k].Son[i]) node[k].Son[i]=rt;
else node[node[k].Son[i]].Next=rt,q.push(node[k].Son[i]);
}
}
}
}
inline void AC_Automation()//AC自动机的核心代码
{
register int i,j,x=rt;
for(GetNext(),i=0;i<len;++i)
{
if(!(x=node[x].Son[GetPos(st[i])])) {x=rt;continue;}
int p=x;
while(p)
{
if(!node[p].Vis) node[p].Vis=1;//如果当前节点未访问过,就标记已访问
else break;//如果已访问过,就break
p=node[p].Next;
}
}
}
int main()
{
register int i,j;register string s;
for(read(len),read(n),read_string(st),tot=i=1;i<=n;++i) read_string(s),lens[i]=s.length(),Insert(i,s);
for(AC_Automation(),i=1;i<=n;++i)
{
for(j=lens[i];j>=0;--j)//从后往前枚举当前模式串的每一个前缀
{
if(!j) pc('0'),pc('\n');
else if(node[ans[i][j-1]].Vis) {write(j),pc('\n');break;}//如果当前节点被访问过,就输出答案并枚举下一个模式串
}
}
return fwrite(pp,1,pp_,stdout),0;
}
【BZOJ4327】[JSOI2012] 玄武密码(AC自动机的小应用)的更多相关文章
- BZOJ4327 [JSOI2012] 玄武密码 [AC自动机]
题目传送门 玄武密码 Description 在美丽的玄武湖畔,鸡鸣寺边,鸡笼山前,有一块富饶而秀美的土地,人们唤作进香河.相传一日,一缕紫气从天而至,只一瞬间便消失在了进香河中.老人们说,这是玄武神 ...
- 【BZOJ4327】JSOI2012 玄武密码 AC自动机
[BZOJ4327]JSOI2012 玄武密码 Description 在美丽的玄武湖畔,鸡鸣寺边,鸡笼山前,有一块富饶而秀美的土地,人们唤作进香河.相传一日,一缕紫气从天而至,只一瞬间便消失在了进香 ...
- BZOJ 4327 [JSOI2012]玄武密码 (AC自动机)
题目链接: https://www.lydsy.com/JudgeOnline/problem.php?id=4327 题解: 做法挺显然,建出AC自动机之后在上面跑,标记所有走过的点,然后再进行递推 ...
- BZOJ4327 JSOI2012玄武密码(AC自动机)
当然可以在SA上二分答案,但看起来会被卡log.考虑对模板串建出AC自动机,用母串在上面跑,标记上所有能到达的点.注意到达某个点时需要标记所有其通过fail指针可以走到的点,如果遇到一个标记过的点就可 ...
- 【AC自动机】bzoj4327: JSOI2012 玄武密码
题目思路没话讲:主要是做题时候的细节和经验 Description 在美丽的玄武湖畔,鸡鸣寺边,鸡笼山前,有一块富饶而秀美的土地,人们唤作进香河.相传一日,一缕紫气从天而至,只一瞬间便消失在了进香河中 ...
- Vijos P1951 玄武密码 (AC自动机)
描述 在美丽的玄武湖畔,鸡鸣寺边,鸡笼山前,有一块富饶而秀美的土地,人们唤作进香河.相传一日,一缕紫气从天而至,只一瞬间便消失在了进香河中.老人们说,这是玄武神灵将天书藏匿在此. 很多年后,人们终于在 ...
- TZOJ 5986 玄武密码(AC自动机)
描述 在美丽的玄武湖畔,鸡鸣寺边,鸡笼山前,有一块富饶而秀美的土地,人们唤作进香河.相传一日,一缕紫气从天而至,只一瞬间便消失在了进香河中.老人们说,这是玄武神灵将天书藏匿在此. 很多年后,人们终于在 ...
- BZOJ 4327: JSOI2012 玄武密码 后缀自动机
Code: #include<bits/stdc++.h> #define setIO(s) freopen(s".in","r",stdin) # ...
- BZOJ4327 : JSOI2012 玄武密码
对所有询问串建立AC自动机. 然后将母串在AC自动机上跑,每走到一个点x,从x点出发沿着fail指针能到的所有前缀都是匹配成功的,暴力向上走,碰到走过的就break,这样每个点最多只会被标记一次. 时 ...
- BZOJ4327:[JSOI2012]玄武密码(SAM)
Description 在美丽的玄武湖畔,鸡鸣寺边,鸡笼山前,有一块富饶而秀美的土地,人们唤作进香河.相传一日,一缕紫气从天而至,只一瞬间便消失在了进香河中.老人们说,这是玄武神灵将天书藏匿在此. ...
随机推荐
- python web开发之flask框架学习(1) 创建flask项目
python 开发越来越火,作为菜鸟,也应该学习一下,感觉还可以,记录下来,方便学习参考. 不管做什么开发首先肯定是安装环境,这里我用的是pycharm,python3.如果不清楚怎么安装环境可以去网 ...
- 通过jQuery实现AJAX
通过jQuery实现AJAX > 使用get和getJSON都会有缓存问题,并且使用get方法不能传送较多的数据. 问题: 在IE浏览器中,get请求使用ajax存在缓存问题,会使用上一次请求的 ...
- 自定义标签报 无法为TAG [my2:hello]加载标记处理程序类[null]
今天练习jsp自定义标签的时候,等我写好全部和检查万无一失的时候.执行然后报错了 无法为TAG [my2:hello]加载标记处理程序类[null] 我反复检查代码,发现代码也没什么问题.后面通过百度 ...
- 方程的解_NOI导刊2010提高(01) 组合数
题目描述 佳佳碰到了一个难题,请你来帮忙解决. 对于不定方程a1+a2+…+ak-1+ak=g(x),其中k≥2且k∈N,x是正整数,g(x)=x^x mod 1000(即x^x除以1000的余数), ...
- MQ 重复消费如何解决?
1. 使用幂等操作 乐观锁:每个数据有一个版本号,和当前版本号相同的时候进行更新 去重表(缓存): 唯一性索引,如果已经存在值了就不行更新 2. 算法 两个链表是否相交? 3.redis 集合相交的 ...
- IfmContextHolder(ThreadLocal)
package com.yundaex.wms.config; public class IfmContextHolder { private static final ThreadLocal< ...
- py---------网络编程
一.软件开发架构 我们了解的涉及到两个程序之间通讯的应用大致可以分为两种: 第一种是应用类:qq.微信.网盘.优酷这一类是属于需要安装的桌面应用 第二种是web类:比如百度.知乎.博客园等使用浏览器访 ...
- Java文件与io——常见字符编码
在计算机世界里,任何的文字都是以指定的编码方式存在的. 常见编码有:ISO8859-1.GBK/GB2312.unicode.UTF ISO8859-1:编码属于单字节编码,最多只能表示0-255的字 ...
- (转)KICKSTART无人值守安装
KICKSTART无人值守安装 导言 作为中小公司的运维,经常会遇到一些机械式的重复工作,例如:有时公司同时上线几十甚至上百台服务器,而且需要我们在短时间内完成系统安装. 常规的办法有什么? 光盘安装 ...
- 爱上MVC~业务层刻意抛出异常,全局异常的捕获它并按格式返回
回到目录 对于业务层的程序的致命错误,我们一直的做法就是直接抛出指定的异常,让程序去终断,这种做法是对的,因为如果一个业务出现了致命的阻塞的问题,就没有必要再向上一层一层的返回了,但这时有个问题,直接 ...