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. oracle dmp文件的导入导出

    一.命令行方式 exp 用户名/密码@库名 file=文件位置.dmp owner=用户名 imp 用户名/密码@库名 file=文件位置.dmp 注意 : 导入过程若有的表已经存在可能会报错,可以全 ...

  2. keil mdk uvision使用技巧

    语法检测&代码提示 中文友好: tab 可以选中一大块代码,一起缩进 快速注释 先选中你要注释的代码区,然后右键,选择Advanced,Comment Selection 就可以了 查找替换 ...

  3. JavaEE JDBC RowSet行集

    RowSet行集 @author ixenos 应用背景 1.基于结果集的缺点:在与用户的整个交互过程中,必须始终与数据库保持连接 后果:当用户长时间离开时,数据库连接长时间被占用,而这属于稀缺资源: ...

  4. windows 下 iptables

    windows自带的防火墙就可以. 在命令行方式下输入netsh回车,再输入firewall回车,之后想干什么就干什么. 头一次见对图形化防火墙头晕的...

  5. codeforces 363A

    #include<stdio.h>//这题挺有意思小学学的算盘 int main() { int n,i,m; while(scanf("%d",&n)!=EO ...

  6. android开发里跳过的坑——调用已安装视频播放器在有些机器上无效

    调用已安装视频播放器播放未修改之前的代码 private void startPlay(String fileName){ File file = new File(fileName); Intent ...

  7. hdu - 2066 一个人的旅行(基础最短路)

    http://acm.hdu.edu.cn/showproblem.php?pid=2066 把与草儿相连的城市最短距离置为0,然后进行dijkstra,在t个城市里找出距离最近的一个即可. #inc ...

  8. poj——1469 COURSES

    COURSES Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 24192   Accepted: 9426 Descript ...

  9. 详细图解mongodb 3.4.1 win7x64安装

    原文:http://www.cnblogs.com/yucongblog/p/6895983.html 详细图解,记录 win7 64 安装mongo数据库的过程.安装的版本是 MongoDB-win ...

  10. FDMemTable内存表操作

    unit Umemtable; interface uses System.SysUtils, System.Types, System.UITypes, System.Classes, System ...