BZOJ4327 玄武密码 (AC自动机)
来源:互联网 发布:淘宝网中老年春秋装 编辑:程序博客网 时间:2024/04/28 14:13
题目大意
给出一个母串和一些特征串,询问字串能在母串中匹配的最长的前缀的长度。
题解
将特征串一一插入AC自动机并构建fail指针,这样母串匹配的时候走过的路径上的点所代表的前缀就都是可匹配的了。
所以把所有的特征串插入AC自动机后构造fail树,然后把母串在AC自动机上跑一下并在可匹配的点上留下标记就可以了,这里要注意标记一定要顺着fail指针传上去一并打上标记,否则可能会遗漏。然后对于每一个特征串,从叶节点向根节点找标记,找到的第一个标记就是可匹配的最长前缀。
另外说一下,bzoj里面别再用getchar了,会WAWAWA。老老实实用scanf吧。
代码
#include <cstdio>#include <iostream>#include <queue>#include <cstring>using namespace std;#define print(k) cout<<#k<<"="<<k<<endlint turn(char ch) { if(ch=='E') return 0; if(ch=='S') return 1; if(ch=='W') return 2; if(ch=='N') return 3;}const int maxn=int(1e7)+111;int fin[maxn],l[maxn];struct AC_auto { int to[maxn][4],fa[maxn],fail[maxn]; bool cnt[maxn]; int tot; void init() { tot=1; } inline void Insert(char *s,int n,int id) { int now=0; for(int i=0;i<n;i++) { int c=turn(s[i]); if(!to[now][c]) fa[tot]=now, to[now][c]=tot++; now=to[now][c]; } fin[id]=now; l[id]=n; return; } std::queue<int> que; void Build() { fail[0]=-1; que.push(0); while(que.size()) { int u=que.front(); que.pop(); for(int i=0;i<4;i++) if(to[u][i]) { int v=to[u][i], p=fail[u]; if(u==0) {fail[v]=0; que.push(v); continue;} while(~p) { if(to[p][i]) {fail[v]=to[p][i]; break;} p=fail[p]; } if(p==-1) fail[v]=0; que.push(v); } } return; } inline void Get(register int u) { while(~u && !cnt[u]) { cnt[u]=true; u=fail[u]; } return; } void Match(char *s,int n) { register int now=0; for(register int i=0;i<n;i++) { register int c=turn(s[i]); if(to[now][c]) now=to[now][c]; else { int p=fail[now]; while(~p && !to[p][c]) p=fail[p]; if(p==-1) now=0; else now=to[p][c]; } if(!cnt[now]) Get(now); } } inline int Calc(int id) { register int now=fin[id], len=l[id]; while(now && !cnt[now]) { len--; now=fa[now]; } return len; }}atm;int n,m;char org[maxn],s[maxn];int main() {#ifndef ONLINE_JUDGE freopen("input.txt","r",stdin); freopen("output.txt","w",stdout);#endif // ONLINE_JUDGE scanf("%d%d%*c",&n,&m); scanf("%s",org); getchar(); atm.init(); for(int id=1;id<=m;id++) { scanf("%s",s); int len=strlen(s); atm.Insert(s,len,id); } atm.Build(); atm.Match(org,n); if(m==1) {printf("%d",atm.Calc(1)); return 0;} for(int i=1;i<=m;i++) printf("%d\n",atm.Calc(i)); return 0;}
1 0
- [BZOJ4327]JSOI2012 玄武密码(AC自动机)
- BZOJ4327 玄武密码 (AC自动机)
- 【bzoj4327】【JSOI2012】【玄武密码】【AC自动机】
- [BZOJ4327]-[JSOI2012]玄武密码-AC自动机
- [BZOJ4327][JSOI2012] 玄武密码 后缀自动机
- 【JSOI2012】【BZOJ4327】玄武密码
- [BZOJ4327] JSOI2012玄武密码
- bzoj 4327: JSOI2012 玄武密码 (AC自动机)
- BZOJ 4327 【JSOI 2012】 玄武密码 AC自动机+dfs
- bzoj1559 [JSOI2009]密码(AC自动机+状压DP)
- vijos-1951 玄武密码
- 自动机理论(AC自动机)
- AC-自动机(AC-Automachine)
- hdu2222,(ac自动机)
- AC自动机(hdu4057)
- hdu2896(AC自动机)
- hdu3065(AC自动机)
- hdu2222(AC自动机)
- CheckBox的逻辑判断
- CodeForces 622 E.Ants in Leaves(dfs)
- React Native 中的promise对象的踩坑之旅
- Android 使用xml实现边框阴影,背景渐变效果(附有RGB颜色查询对照表)
- list模拟实现
- BZOJ4327 玄武密码 (AC自动机)
- OpenGL实现3D立体显示
- hive UDF开发实例
- dependencies和devDependencies
- imageloader: java.io.IOException: Hostname 'https url' was not verified
- 机器学习基石2-1 Perceptron Hypothesis Set
- Dubbo学习笔记(二)
- 图像拼接现在还有研究的价值吗?有哪些可以研究的点?现在技术发展如何?
- shell脚本打印日期时间