T1 玄武密码 bzoj 4327

题目大意:

一些字符串 求这些字符串的前缀在母串上的最大匹配长度是多少

思路:

对于所有串建立AC自动机

拿母串在自动机上匹配 对所有点打标记 以及对他们的fail打标记

查询每个串标记最长到哪即可

 #include<iostream>
#include<cstdio>
#include<cmath>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<vector>
#include<queue>
#define inf 2139062143
#define ll long long
#define MAXN 10100100
using namespace std;
inline int read()
{
int x=,f=;char ch=getchar();
while(!isdigit(ch)) {if(ch=='-') f=-;ch=getchar();}
while(isdigit(ch)) {x=x*+ch-'';ch=getchar();}
return x*f;
}
struct node{int fail,ch[];}tr[MAXN];
int n,m,vis[MAXN],tot;
char s[MAXN],ch[][];
int hsh(char c)
{
if(c=='E') return ;
if(c=='S') return ;
if(c=='W') return ;
return ;
}
void ins(char *c,int len)
{
int pos=;
for(int i=,k;i<len;i++)
{
k=hsh(c[i]);
if(!tr[pos].ch[k]) tr[pos].ch[k]=++tot;
pos=tr[pos].ch[k];
}
}
int q[MAXN],l=,r=,x;
void build()
{
for(int i=;i<;i++) if(tr[].ch[i]) q[++r]=tr[].ch[i];
while(l<=r)
{
x=q[l++];
for(int i=;i<;i++)
if(tr[x].ch[i]) tr[tr[x].ch[i]].fail=tr[tr[x].fail].ch[i],q[++r]=tr[x].ch[i];
else tr[x].ch[i]=tr[tr[x].fail].ch[i];
}
}
void calc()
{
int pos=,k,x;
for(int i=;i<n;i++)
{
k=hsh(s[i]);
pos=tr[pos].ch[k],vis[pos]=,x=pos;
while(tr[x].fail) vis[x=tr[x].fail]=;
}
}
int query(char *c,int len)
{
int pos=,k,res=;
for(int i=;i<len;i++)
{
k=hsh(c[i]);
pos=tr[pos].ch[k];
if(vis[pos]) res=max(res,i+);
else break;
}
return res;
}
int main()
{
n=read(),m=read();
scanf("%s",s);
for(int i=;i<=m;i++)
{scanf("%s",ch[i]);ins(ch[i],strlen(ch[i]));}
build();calc();
for(int i=;i<=m;i++) printf("%d\n",query(ch[i],strlen(ch[i])));
}

T2 Censoring bzoj 3940

题目大意:

有个串S和一些单词 这些单词都不是其他的子串

每次在S中找到最早出现的列表中的单词,然后从S中删除这个单词

重复这个操作直到S中没有列表里的单词为止 输出最后的S

思路:

对于单词建立自动机

因为单词之间没有包含关系 所以可以暴力匹配

在匹配串S时 用手打栈模拟 如果匹配到end就减去这个单词 pos变为之前的pos

 #include<iostream>
#include<cstdio>
#include<cmath>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<vector>
#include<queue>
#define inf 2139062143
#define ll long long
#define MAXN 100100
using namespace std;
inline int read()
{
int x=,f=;char ch=getchar();
while(!isdigit(ch)) {if(ch=='-') f=-;ch=getchar();}
while(isdigit(ch)) {x=x*+ch-'';ch=getchar();}
return x*f;
}
struct node{int fail,ch[];}tr[MAXN];
int n,m,vis[MAXN],tot,ed[MAXN],top,p[MAXN];
char s[MAXN],ch[MAXN],st[MAXN];
void ins(char *c,int len)
{
int pos=;
for(int i=,k;i<len;i++)
{
k=c[i]-'a';
if(!tr[pos].ch[k]) tr[pos].ch[k]=++tot;
pos=tr[pos].ch[k];
}
ed[pos]=len;
}
int q[MAXN],l=,r=,x;
void build()
{
for(int i=;i<;i++) if(tr[].ch[i]) q[++r]=tr[].ch[i];
while(l<=r)
{
x=q[l++];
for(int i=;i<;i++)
if(tr[x].ch[i]) tr[tr[x].ch[i]].fail=tr[tr[x].fail].ch[i],q[++r]=tr[x].ch[i];
else tr[x].ch[i]=tr[tr[x].fail].ch[i];
}
}
int main()
{
scanf("%s",s);n=strlen(s),m=read();
while(m--) {scanf("%s",ch);ins(ch,strlen(ch));}
build();
for(int i=,pos=;i<n;i++)
{
st[++top]=s[i];
pos=tr[pos].ch[s[i]-'a'],p[top]=pos;
if(ed[pos]) top-=ed[pos],pos=p[top];
}
for(int i=;i<=top;i++) printf("%c",st[i]);
}

T3 单词 bzoj 3172

题目大意:

一篇论文是由许多单词组成 求每个单词分别在论文中出现多少次 (论文为所有单词加#拼接起来)

思路:

建立ac自动机 可以想到如果一个单词出现那么它的fail也一定出现一次

每次加入一个单词对经过的节点加一  把每个节点的值加入它所有fail的值

 #include<iostream>
#include<cstdio>
#include<cmath>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<vector>
#include<queue>
#define inf 2139062143
#define ll long long
#define MAXN 1001000
using namespace std;
inline int read()
{
int x=,f=;char ch=getchar();
while(!isdigit(ch)) {if(ch=='-') f=-;ch=getchar();}
while(isdigit(ch)) {x=x*+ch-'';ch=getchar();}
return x*f;
}
struct node{int fail,ch[];}tr[MAXN];
int n,m,tot,ed[MAXN],g[MAXN],val[MAXN];
char ch[MAXN];
void ins(char *c,int len,int x)
{
int pos=;
for(int i=,k;i<len;i++)
{
k=c[i]-'a';
if(!tr[pos].ch[k]) tr[pos].ch[k]=++tot;
pos=tr[pos].ch[k],val[pos]++;
}
g[x]=pos;
}
int q[MAXN],l=,r=,x;
void build()
{
for(int i=;i<;i++) if(tr[].ch[i]) q[++r]=tr[].ch[i];
while(l<=r)
{
x=q[l++];
for(int i=;i<;i++)
if(tr[x].ch[i]) tr[tr[x].ch[i]].fail=tr[tr[x].fail].ch[i],q[++r]=tr[x].ch[i];
else tr[x].ch[i]=tr[tr[x].fail].ch[i];
}
}
int main()
{
m=read();
for(int i=;i<=m;i++) {scanf("%s",ch);ins(ch,strlen(ch),i);}
build();
for(int i=tot;i>=;i--) val[tr[q[i]].fail]+=val[q[i]];
for(int i=;i<=m;i++) printf("%d\n",val[g[i]]);
}

T4 最短母串 bzoj 1195

题目大意:

n个字符串,要求找到一个最短的字符串T,使得这n个字符串都是T的子串

思路:

① 使用AC自动机 对每个end像状压一样标记 传递到fail上

从a到z bfs 如果bfs到状态访问过所有串 就结束

 #include<iostream>
#include<cstdio>
#include<cmath>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<vector>
#include<queue>
#define inf 2139062143
#define ll long long
#define MAXN 610*(1<<12)
using namespace std;
inline int read()
{
int x=,f=;char ch=getchar();
while(!isdigit(ch)) {if(ch=='-') f=-;ch=getchar();}
while(isdigit(ch)) {x=x*+ch-'';ch=getchar();}
return x*f;
}
struct node{int fail,ch[];}tr[];
int n,m,tot,ed[],t;
char ch[];
void ins(char *c,int len,int x)
{
int pos=;
for(int i=,k;i<len;i++)
{
k=c[i]-'A';
if(!tr[pos].ch[k]) tr[pos].ch[k]=++tot;
pos=tr[pos].ch[k];
}
ed[pos]|=(<<x);
}
int q[],l=,r=,x;
void build()
{
for(int i=;i<;i++) if(tr[].ch[i]) q[++r]=tr[].ch[i];
while(l<=r)
{
x=q[l++];
for(int i=;i<;i++)
if(tr[x].ch[i])
tr[tr[x].ch[i]].fail=tr[tr[x].fail].ch[i],ed[tr[x].ch[i]]|=ed[tr[tr[x].fail].ch[i]],q[++r]=tr[x].ch[i];
else tr[x].ch[i]=tr[tr[x].fail].ch[i];
}
}
struct data {int pos,val;}g[MAXN];
queue <data> que;
int ans[],res,hd,tl,vis[][<<];
void bfs()
{
t=(<<n)-,hd=tl=;que.push((data){,});
while(hd<=tl)
{
int p=que.front().pos,st=que.front().val;que.pop();
if(st==t)
{
while(hd>) ans[++res]=g[hd].val,hd=g[hd].pos;
for(int i=res;i;i--) printf("%c",ans[i]+'A');
return ;
}
for(int i=;i<;i++)
if(!vis[tr[p].ch[i]][st|ed[tr[p].ch[i]]])
{
g[++tl]=(data){hd,i};
que.push((data){tr[p].ch[i],(st|ed[tr[p].ch[i]])});
vis[tr[p].ch[i]][st|ed[tr[p].ch[i]]]=;
}
hd++;
}
}
int main()
{
n=read();
for(int i=;i<n;i++) {scanf("%s",ch);ins(ch,strlen(ch),i);}
build();bfs();
}

② 状压 dp i j 表示 已经加入字符的状态为i  j结尾的最小长度 同时开一个数组记录这个串 方便字符串比较

转移的时候枚举一下不在状态里的字符即可

 #include<iostream>
#include<cstdio>
#include<cmath>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<vector>
#include<queue>
#define inf 2139062143
#define ll long long
using namespace std;
inline int read()
{
int x=,f=;char ch=getchar();
while(!isdigit(ch)) {if(ch=='-') f=-;ch=getchar();}
while(isdigit(ch)) {x=x*+ch-'';ch=getchar();}
return x*f;
}
int n,k,dp[<<][],add[][],ban[],t,res=inf,kd;
char ch[][],ans[<<][][],tmp[];
int calc(char *y,char *x)
{
int l=strlen(y),t=min(strlen(x),strlen(y));
for(int j,i=t;i;i--)
{
for(j=;j<i;j++)
if(x[j]!=y[l-i+j]) break;
if(j==i) return i;
}
return ;
}
void mdf(char *x,char *y,int k)
{
int lx=strlen(x),ly=strlen(y);
for(int i=;i<lx;i++) tmp[i]=x[i];
for(int i=k;i<ly;i++) tmp[lx+i-k]=y[i];
}
int cmp(char *x,char *y)
{
int l=strlen(x);
for(int i=;i<l;i++)
if(x[i]<y[i]) return ;
else if(x[i]>y[i]) return ;
return ;
}
int main()
{
n=read();memset(dp,,sizeof(dp));
for(int i=;i<n;i++) scanf("%s",ch[i]);
for(int i=;i<n;i++)
for(int j=;j<n;j++)
{
if(i==j) continue;
memset(tmp,,sizeof(tmp));
for(int k=,l=;k<strlen(ch[i]);k++)
{
tmp[l++]=ch[i][k];
if(calc(tmp,ch[j])==strlen(ch[j])) ban[j]=;
}
}
for(int i=;i<n;i++) if(!ban[i])
{
if(i==k) {k++;continue;}
memset(ch[k],,sizeof(ch[k]));
for(int j=,l=strlen(ch[i]);j<l;j++) ch[k][j]=ch[i][j];
k++;
}
n=max(,k),t=(<<n)-;
for(int i=;i<n;i++)
for(int j=;j<n;j++)
if(i!=j) add[i][j]=calc(ch[i],ch[j]);
for(int i=;i<n;i++)
{
dp[<<i][i]=strlen(ch[i]);
for(int j=,l=strlen(ch[i]);j<l;j++) ans[<<i][i][j]=ch[i][j];
}
for(int i=;i<t;i++)
for(int j=;j<n;j++)
if(((<<j)&i)==)
{
for(int k=;k<n;k++)
if((<<k)&i)
if(dp[i|(<<j)][j]==dp[i][k]+strlen(ch[j])-add[k][j])
{
mdf(ans[i][k],ch[j],add[k][j]);
if(!cmp(ans[i|(<<j)][j],tmp))
{
memset(ans[i|(<<j)][j],,sizeof(ans[i|(<<j)][j]));
for(int l=;l<dp[i|(<<j)][j];l++)
ans[i|(<<j)][j][l]=tmp[l];
}
}
else if(dp[i|(<<j)][j]>dp[i][k]+strlen(ch[j])-add[k][j])
{
dp[i|(<<j)][j]=dp[i][k]+strlen(ch[j])-add[k][j];
mdf(ans[i][k],ch[j],add[k][j]);
memset(ans[i|(<<j)][j],,sizeof(ans[i|(<<j)][j]));
for(int l=;l<dp[i|(<<j)][j];l++)
ans[i|(<<j)][j][l]=tmp[l];
}
if(i|(<<j)==t&&res==dp[t][j]&&cmp(ans[t][j],ans[t][kd])) kd=j;
if(i|(<<j)==t&&res>dp[t][j]) res=dp[t][j],kd=j;
}
printf("%s",ans[t][kd]);
}

T5 病毒 bzoj 2938

题目大意:

询问是否有一个无限长的01串满足任意一个给出的串都不是它的自串

思路:

把end的标记传递 dfs找环 如果有环就说明可以找到一个满足题意的串

 #include<iostream>
#include<cstdio>
#include<cmath>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<vector>
#include<queue>
#define inf 2139062143
#define ll long long
#define MAXN 30100
using namespace std;
inline int read()
{
int x=,f=;char ch=getchar();
while(!isdigit(ch)) {if(ch=='-') f=-;ch=getchar();}
while(isdigit(ch)) {x=x*+ch-'';ch=getchar();}
return x*f;
}
struct node{int fail,ch[];}tr[MAXN];
int n,m,tot,ed[MAXN],t,vis[MAXN],tag[MAXN];
char ch[MAXN];
void ins(char *c,int len)
{
int pos=;
for(int i=,k;i<len;i++)
{
k=c[i]-'';
if(!tr[pos].ch[k]) tr[pos].ch[k]=++tot;
pos=tr[pos].ch[k];
}
ed[pos]=;
}
int q[MAXN],l=,r=,x;
void build()
{
for(int i=;i<;i++) if(tr[].ch[i]) q[++r]=tr[].ch[i];
while(l<=r)
{
x=q[l++];
for(int i=;i<;i++)
if(tr[x].ch[i])
tr[tr[x].ch[i]].fail=tr[tr[x].fail].ch[i],ed[tr[x].ch[i]]|=ed[tr[tr[x].fail].ch[i]],q[++r]=tr[x].ch[i];
else tr[x].ch[i]=tr[tr[x].fail].ch[i];
}
}
int dfs(int x)
{
vis[x]=;
for(int i=;i<;i++)
{
if(vis[tr[x].ch[i]]) return ;
if(tag[tr[x].ch[i]]||ed[tr[x].ch[i]]) continue;
tag[tr[x].ch[i]]=;
if(dfs(tr[x].ch[i])) return ;
}
vis[x]=;return ;
}
int main()
{
n=read();
for(int i=;i<n;i++) {scanf("%s",ch);ins(ch,strlen(ch));}
build();puts(dfs()?"TAK":"NIE");
}

T6 文本生成器 bzoj 1030

题解链接

蓝书2.4 AC自动机的更多相关文章

  1. 【POJ2778】DNA Sequence 【AC自动机,dp,矩阵快速幂】

    题意 题目给出m(m<=10)个仅仅由A,T,C,G组成的单词(单词长度不超过10),然后给出一个整数n(n<=2000000000),问你用这四个字母组成一个长度为n的长文本,有多少种组 ...

  2. LA_3942 LA_4670 从字典树到AC自动机

    首先看第一题,一道DP+字典树的题目,具体中文题意和题解见训练指南209页. 初看这题模型还很难想,看过蓝书提示之后发现,这实际上是一个标准DP题目:通过数组来储存后缀节点的出现次数.也就是用一颗字典 ...

  3. HDU 2243 考研路茫茫——单词情结(AC自动机+矩阵)

    考研路茫茫——单词情结 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total ...

  4. LA 4670 (AC自动机 模板题) Dominating Patterns

    AC自动机大名叫Aho-Corasick Automata,不知道的还以为是能自动AC的呢,虽然它确实能帮你AC一些题目.=_=|| AC自动机看了好几天了,作用就是多个模式串在文本串上的匹配. 因为 ...

  5. HDU 5164Matching on Array(AC自动机)

    这是BC上的一道题,当时比赛没有做,回头看看题解,说是AC自动机,想着没有写过AC自动机,于是便试着抄抄白书的模板,硬是搞了我数个小时2000ms时限1800过了= = ! 这里就直接贴上BC的结题报 ...

  6. hdu2243之AC自动机+矩阵乘法

    考研路茫茫——单词情结 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Tota ...

  7. HDU 2243考研路茫茫——单词情结 (AC自动机+矩阵快速幂)

    背单词,始终是复习英语的重要环节.在荒废了3年大学生涯后,Lele也终于要开始背单词了. 一天,Lele在某本单词书上看到了一个根据词根来背单词的方法.比如"ab",放在单词前一般 ...

  8. hdu2243 考研路茫茫——单词情结【AC自动机】【矩阵快速幂】

    考研路茫茫——单词情结 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total ...

  9. AC自动机学习笔记-2(Trie图&&last优化)

    我是连月更都做不到的蒟蒻博主QwQ 考虑到我太菜了,考完noip就要退役了,所以我决定还是把博客的倒数第二篇博客给写了,也算是填了一个坑吧.(最后一篇?当然是悲怆のnoip退役记啦QAQ) 所以我们今 ...

随机推荐

  1. selenium--driver.switchTo()-----转

    https://www.cnblogs.com/clairejing/p/9499223.html 在自动化测试中,会遇到多窗口.多iframe.多alert的情况.此时,会使用driver.swit ...

  2. UVa 1600 Patrol Robot(BFS)

    题意: 给定一个n*m的图, 有一个机器人需要从左上角(1,1)到右下角(n,m), 网格中一些格子是空地, 一些格子是障碍, 机器人每次能走4个方向, 但不能连续穿越k(0<= k <= ...

  3. 优先队列重载运算符< 以及初始化列表

    优先队列定义 priority_queue<int, vector<int>, greater<int> >pq; 优先队列重载<运算符 在结构体中定义一个 ...

  4. Django——配置服务器上线

    使用UWSGI和NGINX配置项目上线 首先你得有一个拿得出手的项目 其次,购买了域名,也备案成功了 将settings.py中的DEBUG设置为False 配置Uwsgi 在项目(哪里都可以)中创建 ...

  5. 九度oj 题目1057:众数

    题目1057:众数 时间限制:1 秒 内存限制:32 兆 特殊判题:否 提交:9744 解决:3263 题目描述: 输入20个数,每个数都在1-10之间,求1-10中的众数(众数就是出现次数最多的数, ...

  6. ajax导出excel文件并增加等待动画效果

    html: <button class="btn btn-default" onclick="logToExcel('{:url('userLogToExcel', ...

  7. bzoj3295 [Cqoi2011]动态逆序对 cdq+树状数组

    [bzoj3295][Cqoi2011]动态逆序对 2014年6月17日4,7954 Description 对于序列A,它的逆序对数定义为满足i<j,且Ai>Aj的数对(i,j)的个数. ...

  8. Spring boot 搭配 JPA 生成表注释 和 字段注释

    原文地址:https://blog.csdn.net/qq_39996837/article/details/84717748 由于在数据库表反向生成过程中呢,需要通过jpa自动生成表,并且这个表必须 ...

  9. JVM 总结

    面试 java 虚拟机 jvm 基础 jvm Write Once Run EveryWhere >jar 包可以在任何兼容jvm上运行 >jvm 适配器 屏蔽掉底层差异 >内存管理 ...

  10. git一个本地仓库连接多个远程仓库

    前言:由于公司的GIT是内网服务器,而在家工作访问不了内网服务器,由此想把本地仓库连接一个外网的GIT服务器(码云),方便不在公司时开发. 原文 某些场合,一个git项目需要能同时使用两个甚至多个远程 ...