我做个总结算了下午看了一下AC自动机和学习我的大生物(当然是多谢鑫神了)。。完了要崩。。

1 KMP 只要是学过的人都觉得比较简单吧 但是学不会的人就感觉很难了,我是那种顿悟的然后感觉非常简单的人过程需要自己来体会言传不如身教用身心去体会这个过程就可以成功了。

一种快速匹配子串的东西。具体来说 证明我就不在证了先对自我进行匹配求出nex数组然后和文本串进行匹配考虑这样当我们匹配刚好失配的时候此时还有价值的匹配只能是前面的前缀和当前的东西匹配上了这样才会有价值的匹配不然前面的串往后移动一个距离还是会失配,因为到达改点的时候还是会失配。这样我们每次都利用有价值的匹配实现时间复杂度为O(n);

#include<bits/stdc++.h>
#include<iostream>
#include<cstring>
#include<string>
#include<ctime>
#include<cmath>
#include<iomanip>
#include<algorithm>
#include<queue>
#include<vector>
#include<stack>
#include<cstdio>
#include<map>
#include<deque>
#include<set>
using namespace std;
inline int read()
{
int x=,f=;char ch=getchar();
while(ch<''||ch>''){if(ch=='-')f=-;ch=getchar();}
while(ch>=''&&ch<=''){x=x*+ch-'';ch=getchar();}
return x*f;
}
const int maxn=;
char a[maxn],b[maxn];
int nex[maxn],len,tot;
void KMP()
{
int j=;
nex[]=;
for(int i=;i<=tot;i++)
{
while(j&&b[j+]!=b[i])j=nex[j];
if(b[j+]==b[i])j++;
nex[i]=j;
}
j=;
for(int i=;i<=len;i++)
{
while(j&&b[j+]!=a[i])j=nex[j];
if(a[i]==b[j+])j++;
if(j==tot)
{
printf("%d\n",i-j+);
j=nex[j];
}
}
}
int main()
{
//freopen("1.in","r",stdin);
scanf("%s",a+);scanf("%s",b+);
len=strlen(a+);tot=strlen(b+);
KMP();
for(int i=;i<=tot;i++)printf("%d ",nex[i]);
return ;
}

具体就是这样了真的不清楚的话就自己晚上睡觉前思考一下,体会一下这美妙的过程。。

当然我才知道有扩展KMP开个坑,以后填!

扩展KMP:

2 HASH hash可能是初学者最容易理解的算法了我觉得,因为在一定的程度上它表现出来的是暴力的美学也是干净利索的做法。和字符串联系在一起自然是要进行字符串的hash。字符串的hash 的话我们采用字符赋值或者直接使用ASCll 也行但是这显然很容易就冲突了abc bca 直接GG 这里我们日常的hash是直接采用进制hash来搞一些操作。我们试想 a*p^3+b*p^2+c*p 这样和b*p^3+c*p^2+a*p 这样冲突的几率会非常的小或者说在一定的意义下是不可能冲突的因为这就不是一个hash了变成了一个p进制的数字对于这样的数字每个字符串都只能对应一个数字又何谈来冲突呢?数字太大存不下啊map!这个我还不如直接mapstring呢!也对哦那只能取模了模数大一点减少冲突几率然后操作是祷告自己欧皇附身取得模数没有冲突!挂链法好像不太好用嘞。。那我也没办法了。我们有h[i]数组表示前i个字符的hash值然后我们可以求出来任何一段的hash值只要不冲突我们这个就可以实现O(1)判断两个字符串是否相同了!!!这样的话写字符串的匹配应该也是O(1)的。本来是要表演一下hash 的但是无奈map还是比较好用的我没办法只能使用了hash。抱歉会就行了。

方一道比较有意思的hash题可惜了我并没有成就感因为这道题本质上并不是我思考出来的哎。

这道题比较有意思求一个字符串中出现的东西 搞一波事情吧对于最长的我们把整个m便利完了之后一定能够求出,此时对于某个点我们应该二分一个长度使其达到答案这个答案相当的不好判断啊。

但是转换一个问题 对于一个i这个单词我们主席树中开这个东西然后查询就行了 啊二分+可持久化一下即可。妙!一个字符串的题目被转换成了数据结构的题目我也是佩服。

考虑一种更优的方法是尺取法 对于 l r r向右移动当移动到某个点的时候此时单词都有了 l向右移动此时不断的更新答案然后r再向右我们O(n)的时间貌似是求出了这个东西采用hash的话我想是可以O(n)的操作难度较高我们采用一定不会冲突的map 此时我们直接开个数组表示某个字符串出现了几次即可。完事了。

//#include<bits/stdc++.h>
#include<iostream>
#include<queue>
#include<iomanip>
#include<cctype>
#include<cstdio>
#include<deque>
#include<utility>
#include<cmath>
#include<ctime>
#include<cstring>
#include<string>
#include<cstdlib>
#include<vector>
#include<algorithm>
#include<stack>
#include<map>
#include<set>
#include<bitset>
#define max(x,y) ((x)>(y)?(x):(y))
#define min(x,y) ((x)>(y)?(y):(x))
#define INF 1000000000
#define ll long long
#define R register
#define mod 1000000007
using namespace std;
inline void put(R int x)
{
x<?putchar('-'),x=-x:;
R int num=;char ch[];
while(x)ch[++num]=x%+'',x/=;
num==?putchar(''):;
while(num)putchar(ch[num--]);
putchar('\n');return;
}
const int MAXN=;
int n,m,num,ans,s,answer=MAXN;
int vis[MAXN],cnt[MAXN];
map<string,int>k;
string a,b[MAXN];
int main()
{
ios::sync_with_stdio(false);
cin>>n;
for(int i=;i<=n;++i)
{
cin>>a;
if(!k[a])k[a]=++s;
//cout<<a<<endl;
}
cin>>m;
for(int i=;i<=m;++i)
{
cin>>b[i];
vis[k[b[i]]]=;
//cout<<b[i]<<endl;
}
for(int i=;i<=s;++i)if(vis[i])++ans;
if(ans==){put(ans),put();return ;}
for(int i=,j=;j<=m;++j)
{
int g=k[b[j]];
if(g)
{
++cnt[g];
if(cnt[g]==)++num;
}
while(num==ans)
{
//cout<<j<<' '<<i<<endl;
answer=min(answer,j-i);
++i;g=k[b[i]];
if(g)
{
--cnt[g];
if(cnt[g]==)--num;
}
}
}
put(ans);
put(answer);
return ;
}

这种尺取法显然是正确的如果非要证明的话我会采用一种答案最优性原则证明答案一定是答案所以这是正确的。

Trie 字典树啦很简单的东西可持久化的东西我想想好像是一个有根的东西等会我复习一下嘞。

首先是字典树我们对于根出发建立每一个单词的路径然后查询的时候直接查询即可。时间。

注意这里时间是总插入Trie数的字符串的长度而空间则是MAX最长子串*根的数量*子串数量*子串的最大数集。

很朴素的一道题目询问每篇文章出现了多少个单词其实就是建一颗Trie树在上面跑即可 然后我们考虑建文章的Trie树那么复杂度就是mn*20当然可以过但是我想AC自动机的话这个复杂度应该是O(m*5000)左右吧要快一点当然计算一下空间吧建文章的Trie 空间:n*5000*26=130000000*4=520000000b=520000kb=520MB刚好爆炸。。空间就给了128肿么办我的办法是直接开char 存。然后可以存下。

//#include<bits/stdc++.h>
#include<iostream>
#include<queue>
#include<iomanip>
#include<cctype>
#include<cstdio>
#include<deque>
#include<utility>
#include<cmath>
#include<ctime>
#include<cstring>
#include<string>
#include<cstdlib>
#include<vector>
#include<algorithm>
#include<stack>
#include<map>
#include<set>
#include<bitset>
#define max(x,y) ((x)>(y)?(x):(y))
#define min(x,y) ((x)>(y)?(y):(x))
#define INF 1000000000
#define ll long long
#define R register
#define l(x) c[x][0]
#define r(x) c[x][1]
using namespace std;
char buf[<<],*fs,*ft;
inline char getc()
{
return (fs==ft&&(ft=(fs=buf)+fread(buf,,<<,stdin),fs==ft))?:*fs++;
}
inline int read()
{
R int x=,f=;char ch=getchar();
while(ch<''||ch>''){if(ch=='-')f=-;ch=getchar();}
while(ch>=''&&ch<=''){x=x*+ch-'';ch=getchar();}
return x*f;
}
inline void put(R int x)
{
x<?putchar('-'),x=-x:;
R int num=;char ch[];
while(x)ch[++num]=x%+'',x/=;
num==?putchar(''):;
while(num)putchar(ch[num--]);
putchar('\n');return;
}
const int MAXN=,maxn=;
int n,m,cnt,flag=;
int trie[MAXN][],p;
int c[];
bool vis[MAXN];
char a[][MAXN][];
char b[maxn][];
bitset<>used[maxn];
inline void insert(int i,int j)
{
int len=strlen(a[i][j]);p=;
for(int k=;k<len;++k)
{
int now=a[i][j][k]-'a';
if(!trie[p][now])trie[p][now]=++cnt;
p=trie[p][now];
}
vis[p]=;
}
inline void calculate(int j)
{
int len=strlen(b[j]);p=;
for(int k=;k<len;++k)
{
if(b[j][k]<'a'||b[j][k]>'z')continue;
int now=b[j][k]-'a';
if(!trie[p][now])return;
p=trie[p][now];
}
if(vis[p])flag=;
}
int main()
{
n=read();
for(int i=;i<=n;++i)
{
c[i]=read();
for(int j=;j<=c[i];++j)scanf("%s",a[i][j]);
}
m=read();
for(int i=;i<=m;++i)scanf("%s",b[i]);
for(int i=;i<=n;++i)
{
memset(trie,,sizeof(trie));
memset(vis,,sizeof(vis));
cnt=;
for(int j=;j<=c[i];++j)insert(i,j);
for(int j=;j<=m;++j)
{
flag=;
calculate(j);
if(flag)used[j][i]=;
}
}
for(int j=;j<=m;++j)
{
flag=;
for(int i=;i<=n;++i)
if(used[j][i])
{
if(flag==){flag=;printf("%d",i);}
else printf(" %d",i);
}
putchar('\n');
}
return ;
}

一直wa 的原因是vis数组竟然没开 不是开了我又删了。。

一道简单的Trie树+dp 暴力dp 出奇迹A了。

//#include<bits/stdc++.h>
#include<iostream>
#include<queue>
#include<iomanip>
#include<cctype>
#include<cstdio>
#include<deque>
#include<utility>
#include<cmath>
#include<ctime>
#include<cstring>
#include<string>
#include<cstdlib>
#include<vector>
#include<algorithm>
#include<stack>
#include<map>
#include<set>
#include<bitset>
#define max(x,y) ((x)>(y)?(x):(y))
#define min(x,y) ((x)>(y)?(y):(x))
#define INF 1000000000
#define ll long long
#define R register
#define l(x) c[x][0]
#define r(x) c[x][1]
using namespace std;
char buf[<<],*fs,*ft;
inline char getc()
{
return (fs==ft&&(ft=(fs=buf)+fread(buf,,<<,stdin),fs==ft))?:*fs++;
}
inline int read()
{
R int x=,f=;char ch=getchar();
while(ch<''||ch>''){if(ch=='-')f=-;ch=getchar();}
while(ch>=''&&ch<=''){x=x*+ch-'';ch=getchar();}
return x*f;
}
inline void put(R int x)
{
x<?putchar('-'),x=-x:;
R int num=;char ch[];
while(x)ch[++num]=x%+'',x/=;
num==?putchar(''):;
while(num)putchar(ch[num--]);
putchar('\n');return;
}
const int MAXN=;
int n,p,cnt,m,maxx;
char b[],a[MAXN];
int trie[][];
int vis[];
int f[MAXN];
inline void insert()
{
int len=strlen(b+);p=;
for(int i=;i<=len;++i)
{
int now=b[i]-'a';
if(!trie[p][now])trie[p][now]=++cnt;
p=trie[p][now];
}
vis[p]=;
}
inline int query(int l,int r)
{
p=;
for(int i=l;i<=r;++i)
{
int now=a[i]-'a';
if(!trie[p][now])return ;
p=trie[p][now];
}
if(vis[p])return ;
return ;
}
int main()
{
n=read();m=read();
for(int i=;i<=n;++i)scanf("%s",b+),insert();
for(int i=;i<=m;++i)
{
scanf("%s",a+);
memset(f,,sizeof(f));
maxx=;f[]=;
int len=strlen(a+);
for(int j=;j<=len;++j)
{
int flag=;
for(int k=j-<?:j-;k<j;++k)
{
if(!f[k])continue;
flag=;
f[j]|=f[k]&query(k+,j);
if(f[j])break;
//cout<<k<<' '<<f[k]<<endl;
//cout<<query(k+1,j)<<endl;
}
if(f[j])maxx=max(maxx,j);
if(!flag)break;
}
put(maxx);
}
return ;
}

AC自动机 为什么要叫自动很简单因为它可以自动的匹配模式串我们继续我们的话题上午有点跑偏了。。。

自动之意取自会自己进行匹配而不需要人工的让其专门的操作原因在于一个fail数组 自闭了 我不写了。

KMP,HASH,Trie,AC自动机的更多相关文章

  1. KMP,Trie,AC自动机题目集

    字符串算法并不多,KMP,trie,AC自动机就是其中几个最经典的.字符串的题目灵活多变也有许多套路,需要多做题才能体会.这里收集了许多前辈的题目做个集合,方便自己回忆. KMP题目:https:// ...

  2. AC自动机及KMP练习

    好久都没敲过KMP和AC自动机了.以前只会敲个kuangbin牌板子套题.现在重新写了自己的板子加深了印象.并且刷了一些题来增加自己的理解. KMP网上教程很多,但我的建议还是先看AC自动机(Trie ...

  3. AC自动机讲解+[HDU2222]:Keywords Search(AC自动机)

    首先,有这样一道题: 给你一个单词W和一个文章T,问W在T中出现了几次(原题见POJ3461). OK,so easy~ HASH or KMP 轻松解决. 那么还有一道例题: 给定n个长度不超过50 ...

  4. AC自动机详解 (P3808 模板)

    AC自动机笔记 0.0 前言 哇,好久之前就看了 KMP 和 Trie 树,但是似乎一直没看懂 AC自动机?? 今天灵光一闪,加上之前看到一些博客和视频,瞬间秒懂啊... 其实这个玩意还是蛮好理解的. ...

  5. AC自动机简明教程

    不会kmp和Trie树的请点击右上角X. AC自动机与kmp的唯一区别便是从单模式串变成了多模式串. 那么与kmp相同,AC自动机中的fail指针是指向当前状态的最长后缀. 当然这个后缀要在Trie树 ...

  6. AC自动机讲解超详细

    begin:2019/5/2 感谢大家支持! AC自动机详细讲解 AC自动机真是个好东西!之前学KMP被Next指针搞晕了,所以咕了许久都不敢开AC自动机,近期学完之后,发现AC自动机并不是很难,特别 ...

  7. AC自动机

    AC自动机,全称Aho-Corasick自动机.如果没记错的话好像就是前缀自动机. 其实AC自动机就是KMP上树的产物.理解了KMP,那AC自动机应该也是很好理解的. 与KMP类似,AC自动机也是扔一 ...

  8. 【BZOJ】1030: [JSOI2007]文本生成器(递推+ac自动机)

    http://www.lydsy.com/JudgeOnline/problem.php?id=1030 其实做了1009也不会感到很难了,无非将kmp变成了ac自动机. 设f[i,j]表示前i个串当 ...

  9. bzoj3940&&bzoj3942 Ac自动机||kpm算法

    方法就是维护一个动态栈 记录栈的每一位匹配到串的哪一位的编号 第一道kmp第二道ac自动机 自己理会 #include<cstdio> #include<cstring> #i ...

随机推荐

  1. js 字符串转方法,this域绑定

    闲着没事,开发一个列表页面配置的功能,其中涉及到了按钮点击事件,在页面进行编辑,保存到数据库中.写好的js脚本,function是字符串格式,所以要让生成的脚本生效,还要做一些操作. 1.首先保存在数 ...

  2. IBM & Howdoo – 区块链上的智能社交

    原文链接:https://www.themsphub.com/ibm-howdoo-smart-social-on-the-blockchain 我们很高兴地宣布,我们成为了一个令人兴奋的新社交网络的 ...

  3. 成熟度模型:企业规模化推广敏捷和DevOps利器

    摘要: 本文介绍了成熟度模型在软件开发行业的应用,重点阐述了成熟度模型对于敏捷和DevOps在企业中进行规模化推广的价值,探讨了成熟度模型的设计原则,并对于如何明智使用成熟度模型给出了建议. 导言 在 ...

  4. python 并发专题(十二):基础部分补充(四)协程

    相关概念: 协程:一个线程并发的处理任务 串行:一个线程执行一个任务,执行完毕之后,执行下一个任务 并行:多个CPU执行多个任务,4个CPU执行4个任务 并发:一个CPU执行多个任务,看起来像是同时执 ...

  5. Threejs实现滴滴官网首页地球动画

    .katex { display: block; text-align: center; white-space: nowrap; } .katex-display > .katex > ...

  6. Video 自动播放

    先说ios ios之前的政策是视频只能在用户主动操作后才能播放,且播放时必须全屏. 随着 iOS 10 的正式发布,Safari 也迎来了大量更新,首先划出重点:1)iOS 10 Safari 支持特 ...

  7. bzoj2296【POJ Challenge】随机种子*

    bzoj2296[POJ Challenge]随机种子 题意: 求一个≤10^16的数,使这个数包含123456789且为x的倍数.x≤1000000. 题解: 16-6刚好等于10.因此我们可以直接 ...

  8. 你真的清楚DateTime in C#吗?

    DateTime,就是一个世界的大融合.   日期和时间,在我们开发中非常重要.DateTime在C#中,专门用来表达和处理日期和时间. 本文算是多年使用DateTime的一个总结,包括DateTim ...

  9. 011.Nginx防盗链

    一 盗链 1.1 盗链概述 盗链指的是在自己的界面展示非本服务器上的内容,通过技术手段获得其他服务器的资源.绕过他人资源展示页面,在自己页面向用户提供此内容,从而减轻自己服务器的负担,因为真实的空间和 ...

  10. SQL 给某字段添加汉字却显示??

    错误展示: 解决方案: 1.在要修改的数据库上单击鼠标右键,并选择“属性”.   2.在弹出的数据库属性窗口中点击“选择页”中的“选项”.   3.将排序规则由默认的SQL_Latin1_Genera ...