坑什么的随便就挖好了。
Trie - 字典树
概述
也叫前缀树,用来保存字符串集合。从根到每一个单词结点的路径就是一个单词。
模板见ACAM.
Trie还可以改进,可以将后缀相同的单词收束,学有余力来过来看。
例1 [LA3942] Remember the Word
- [Description]
给定最多4000个长度不超过100的单词,将一个长度不超过300000的字符串拆解成单词有多少成拆发。
- [Solution]
DP+Trie.先预处理哪些区间[i,j]是单词(枚举+判断需O(n2),我们可以直接从Trie下手),再线性转移。
例2 [UVa11732] "strcmp()"Anyone?
- [Description]
给定不超过4000个长度不超过1000的字符串,求他们两两公共前缀总和。
- [Solution]
在Trie上操作。
MP - 最小表示法
概述
大半年前看过一遍然后完全不记得了啊,再看的时候傻逼得吓人qwq
字符串什么的就是容易忘…
一种判循环同构的工具。
[Code]
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| const int maxn=1000; char s[maxn]; void MP(){ int l=0,r=1,k=0,t; while(l<n && r<n){ k=0; while(s[l+k]==s[r+k]) k++; if(s[l+k]<s[r+k]) r=r+k+1; else l=l+k+1; if(l==r) r++; if(max(l,r)>=n) t=min(l,r); } for(int i=t;i<t+n;i++) putchar(s[i]); }
|
KMP - 看*片
详述
请移步 >> KMP算法 | Knuth–Morris–Pratt algorithm
例1 [LA3026] Period
- [Description]
求长度不超过106的字符串每个前缀的最长循环节,若不存在则不输出。
- [Hint]
如串”aabaabaabaab”,ans[2]=1,ans[6]=2,ans[9]=3,ans[12]=4
- [Solution]
非常有趣的题目,性质题。
计算字符串的next数组,若next[i]!=0 && i%(i-next[i])==0,则有s[next[i]+1]~s[i]为循环节,进而算出循环次数。
EXKMP - 扩展看*片
就是比KMP的同时求一个extend数组咯。
1 2 3 4 5 6 7 8 9 10 11 12 13
| const int maxn=100; int next[maxn],extend[maxn]; char s[maxn],len1,t[maxn],len2; void EXKMP(){ for(int i=0,j=-1,a,p;i<len1;i++){ if(j<0 || i+next[i-a]>=p){ if(j<0) j=0,p=i; while(s[p]==t[j] && p<len1 && j<len2) p++,j++; extend[i]=j,a=i; } else extend[i]=next[i-a]; } }
|
Manacher - 马拉车
选了一篇讲得比较清晰的 >> http://blog.csdn.net/xingyeyongheng/article/details/9310555
需要注意的是文中为当前匹配搭配i+k,i为能匹配到最远的中心位置。
还有就是s[0]初始化成未知字符防止while的的时候越界。
1 2 3 4 5 6 7 8 9 10 11 12
| scanf("%s",s+1); int n=strlen(s+1),ans=0; s[0]='*',s[2*n+1]='#'; for(int i=n;i;i--) s[2*i]=s[i],s[2*i-1]='#'; for(int i=1,id=0;i<=2*n+1;i++){ if(id+p[id]>i) p[i]=min(p[2*id-i],p[id]+id-i); else p[i]=1; while(s[i+p[i]]==s[i-p[i]]) p[i]++; if(id+p[id]<i+p[i]) id=i; ans=max(ans,p[i]-1); } printf("%d\n",ans);
|
ACAM - AC自动机
ACAM=Trie+KMP
ACAM用于多个子串和母串的匹配,可以想到,KMP是线性结构上的字符串匹配,而AC自动机是在Trie上的匹配,详情见代码(过HDU2222测试)。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59
| struct ACAM{ int val; ACAM*nxt[26],*fail; ACAM(){ val=0; fail=NULL; for(int i=0;i<26;i++) nxt[i]=NULL; } void init(){ if(!this) return; for(int i=0;i<26;i++) if(nxt[i]){ this->nxt[i]->init(); delete nxt[i]; nxt[i]=NULL; } } void insert(char*s){ ACAM*u=this; int len=strlen(s); for(int i=0;i<len;i++){ int v=s[i]-'a'; if(!u->nxt[v]) u->nxt[v]=new ACAM; u=u->nxt[v]; } u->val++; } void getFail(){ queue<ACAM*> q; this->fail=this; for(int i=0;i<26;i++) if(this->nxt[i]){ q.push(this->nxt[i]); this->nxt[i]->fail=this; } while(!q.empty()){ ACAM*r=q.front(); q.pop(); for(int i=0;i<26;i++){ ACAM*&u=r->nxt[i],*v=r->fail; if(!u) continue; else q.push(u); while(v!=this && !v->nxt[i]) v=v->fail; u->fail=v->nxt[i]?v->nxt[i]:this; } } } int find(char*s){ int ans=0; ACAM*k=this; int len=strlen(s); for(int i=0;i<len;i++){ int c=s[i]-'a'; while(k!=this && !k->nxt[c]) k=k->fail; k=k->nxt[c]?k->nxt[c]:this; ACAM*k1=k; while(k1!=this && k1->val>0){ ans+=k1->val; k1->val=-1; k1=k1->fail; } } return ans; } };
|
SA- 后缀数组
lz写了一个小时忘记保存,一瞬间差点跳出窗外。呵呵。不管了。
直接丢代码。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
| struct SA{ static const int maxn=10000+10; int s[maxn]; int sa[maxn],height[maxn],n; SA(){ scanf("%s",s); n=strlen(s); } void getSA(){ int x[maxn],y[maxn],c[maxn]; for(int i=0;i<n;i++) c[x[i]=s[i]]++; for(int i=1;i<=2;i++) c[i]+=c[i-1]; for(int i=n-1;i>=0;i--) sa[--c[x[i]]]=i; for(int k=1,m=2,p=0;k<=n && p<n;k<<=1,m=p){ p=0; for(int i=n-k;i<n;i++) y[p++]=i; for(int i=0;i<n;i++) if(sa[i]>=k) y[p++]=sa[i]-k; for(int i=0;i<m;i++) c[i]=0; for(int i=0;i<n;i++) c[x[y[i]]]++; for(int i=1;i<m;i++) c[i]+=c[i-1]; for(int i=n-1;i>=0;i--) sa[--c[x[y[i]]]]=y[i]; p=1,y[sa[0]]=0; for(int i=1;i<n;i++) y[sa[i]]=x[sa[i-1]]==x[sa[i]] && x[sa[i-1]+k]==x[sa[i]+k]?p-1:p++; swap(x,y); } } void getHeight(){ int rank[maxn]; for(int i=0;i<n;i++) rank[sa[i]]=i; for(int i=0,k=0;i<n;i++){ if(k) k--; int j=sa[rank[i]-1]; while(s[i+k]==s[j+k]) k++; height[rank[i]]=k; } } }sa;
|
SAM - 后缀自动机
PAM - 回文自动机