后缀自动机
Posted 菁芜·Firmamentfell
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了后缀自动机相关的知识,希望对你有一定的参考价值。
kuangbin 的模板
//begin{ kuangbin SAM } struct SAM_Node { SAM_Node *fa, *next[CHAR]; int len, id, pos; SAM_Node(int _len = 0): fa(0), len(_len), id(0), pos(0) {memset(next, 0, sizeof(next));} }; SAM_Node SAM_node[MAXN * 2], *SAM_root, *SAM_last; int SAM_size; SAM_Node *newSAM_Node(int len) {SAM_node[SAM_size] = SAM_Node(len); SAM_node[SAM_size].id = SAM_size; return &SAM_node[SAM_size++];} SAM_Node *newSAM_Node(SAM_Node *p) {SAM_node[SAM_size] = *p; SAM_node[SAM_size].id = SAM_size; return &SAM_node[SAM_size++];} void SAM_init() {SAM_size = 0; SAM_root = SAM_last = newSAM_Node(0); SAM_node[0].pos = 0;} void SAM_add(int x, int len) { SAM_Node *p = SAM_last, *np = newSAM_Node(p->len + 1); np->pos = len; SAM_last = np; for(; p && !p->next[x]; p = p->fa) p->next[x] = np; if(!p) { np->fa = SAM_root; return;} SAM_Node *q = p->next[x]; if(q->len == p->len + 1) { np->fa = q; return;} SAM_Node *nq = newSAM_Node(q); nq->len = p->len + 1; q->fa = nq; np->fa = nq; for(; p && p->next[x] == q; p = p->fa) p->next[x] = nq; } void SAM_build(char *s) { SAM_init(); int len = strlen(s); for(int i = 0; i < len; i++) SAM_add(s[i] - ‘a‘, i + 1); } int topocnt[MAXN]; SAM_Node *topsam[MAXN * 2]; void topo() { int n = strlen(s); SAM_build(s); memset(topocnt, 0, sizeof(topocnt)); for(int i = 0; i < SAM_size; i++)topocnt[SAM_node[i].len]++; for(int i = 1; i <= n; i++)topocnt[i] += topocnt[i - 1]; for(int i = 0; i < SAM_size; i++)topsam[--topocnt[SAM_node[i].len]] = &SAM_node[i]; } // end{kaungbin SAM}
求最长公共子串长度
char s1[MAXN], s2[MAXN]; void solve() { gets(s1); gets(s2); SAM_build(s1); int ans = 0; SAM_Node *p = SAM_root; for(int i = 0, t = 0, len = strlen(s2); i < len; ++i) { if(p->next[s2[i] - ‘a‘]) { p = p->next[s2[i] - ‘a‘]; t++; } else { while(p != NULL && !p->next[s2[i] - ‘a‘]) p = p->fa; if(p == NULL) p = SAM_root, t = 0; else t = p->len + 1, p = p->next[s2[i] - ‘a‘]; } ans = std::max(ans, t); } printf("%d\n", ans); }
求字典序最小循环移位(可用最小表示法)
char s1[MAXN]; void solve() { gets(s1); SAM_build(s1); int len = strlen(s1); for(int i = 0; i < len; ++i) SAM_add(s1[i] - ‘a‘, len + i + 1); SAM_Node *p = SAM_root; for(int i = 0, t = 0, len = strlen(s1); i < len; ++i) { int j = 0; while(p->next[j] == NULL && j < 26) j++; p = p->next[j]; } int ans = p->pos - len + 1; printf("%d\n", ans); }
依次输出长度为 i (from 1 to |s|) 的所有子串中出现的最多次数
const int MAXN = 500000+7;
// r(表示当前状态可以在多少个位置上出现)
// mi(当前状态能接受的串的最短长度,即 par->val+1)
int r[MAXN],mi[MAXN],ret[MAXN];
void solve() {
gets(s); topo();
int len = strlen(s);
SAM_Node *p = SAM_root;
for(int i = 0; i < len; ++i){
p = p->next[s[i]-‘a‘];
r[p->id] = 1;
}
for(int i = SAM_size - 1; i > 0; --i) {
p = topsam[i];
r[p->fa->id] += r[p->id];
mi[p->id] = mi[p->fa->id];
}
for(int i = 1;i < SAM_size;++i){
p = topsam[i];
ret[p->len] = std::max(ret[p->len],r[p->id]);
//printf("f[%d]=%d\n",p->len,r[p->id]);
}
for(int i = len-1;i>0;--i) ret[i] = std::max(ret[i+1],ret[i]);
for(int i = 1;i <= len;++i){
printf("%d\n",ret[i]);
}
}
上面代码中 MAXN = 250000+7 时返回 WA
~~~~(>_<)~~~~
To be continued ... ...
以上是关于后缀自动机的主要内容,如果未能解决你的问题,请参考以下文章
我的Android进阶之旅关于Android平台获取文件的mime类型:为啥不传小写后缀名就获取不到mimeType?为啥android 4.4系统获取不到webp格式的mimeType呢?(代码片段
我的Android进阶之旅关于Android平台获取文件的mime类型:为啥不传小写后缀名就获取不到mimeType?为啥android 4.4系统获取不到webp格式的mimeType呢?(代码片段