后缀自动机学习笔记

Posted poorpool

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了后缀自动机学习笔记相关的知识,希望对你有一定的参考价值。

hihocoder系列

这是一个系列讲解,好康的,有六集……

构建SAM并求不同子串数

对应第二个讲解

#include <iostream>
#include <cstring>
#include <cstdio>
using namespace std;
typedef long long ll;
int tot, n, maxLen[2000005], minLen[2000005], trans[2000005][26];
int slink[2000005];
char ss[1000005];
int newSamNode(int _maxLen_, int _minLen_, int *_trans_, int _slink_){
    maxLen[++tot] = _maxLen_;
    minLen[tot] = _minLen_;
    slink[tot] = _slink_;
    if(_trans_!=NULL)
        for(int i=0; i<26; i++)
            trans[tot][i] = _trans_[i];
    return tot;
}
int addChar(int u, char ch){
    int c=ch-‘a‘, v=u;
    int z=newSamNode(maxLen[u]+1, -1, NULL, 0);
    while(v && !trans[v][c]){
        trans[v][c] = z;
        v = slink[v];
    }
    if(!v){
        minLen[z] = slink[z] = 1;
        return z;
    }
    int x=trans[v][c];
    if(maxLen[v]+1==maxLen[x]){
        slink[z] = x;
        minLen[z] = maxLen[x] + 1;
        return z;
    }
    int y=newSamNode(maxLen[v]+1, -1, trans[x], slink[x]);
    minLen[y] = maxLen[slink[y]] + 1;
    slink[z] = slink[x] = y;
    minLen[x] = minLen[z] = maxLen[y] + 1;
    while(v && trans[v][c]==x){
        trans[v][c] = y;
        v = slink[v];
    }
    return z;
}
int main(){
    scanf("%s", ss);
    n = strlen(ss);
    int pre=1;
    tot = 1;
    for(int i=0; i<n; i++)
        pre = addChar(pre, ss[i]);
    ll ans=0;
    for(int i=2; i<=tot; i++)
        ans += maxLen[i] - minLen[i] + 1;
    cout<<ans<<endl;
    return 0;
}

长度为 \(k\) 的子串最多出现几次

第三个讲解

#include <iostream>
#include <cstring>
#include <cstdio>
#include <queue>
using namespace std;
int n, tot=1, maxlen[2000005], minlen[2000005], trans[2000005][26];
int slink[2000005], cntendpos[2000005], cnt[2000005], ans[2000005];
char ss[1000005];
queue<int> d;
int newSamNode(int Maxlen, int Minlen, int *Trans, int Slink){
    maxlen[++tot] = Maxlen;
    minlen[tot] = Minlen;
    slink[tot] = Slink;
    if(Trans!=NULL)
        for(int i=0; i<26; i++)
            trans[tot][i] = Trans[i];
    return tot;
}
int addChar(int u, char ch){
    int c=ch-‘a‘, v=u;
    int z=newSamNode(maxlen[v]+1, -1, NULL, 0);
    cntendpos[z] = 1;
    while(v && !trans[v][c]){
        trans[v][c] = z;
        v = slink[v];
    }
    if(!v){
        minlen[z] = slink[z] = cntendpos[z] = 1;
        return z;
    }
    int x=trans[v][c];
    if(maxlen[v]+1==maxlen[x]){
        slink[z] = x;
        minlen[z] = maxlen[x] + 1;
        return z;
    }
    int y=newSamNode(maxlen[v]+1, -1, trans[x], slink[x]);
    minlen[y] = maxlen[slink[y]] + 1;
    slink[x] = slink[z] = y;
    minlen[x] = minlen[z] = maxlen[y] + 1;
    while(v && trans[v][c]==x){
        trans[v][c] = y;
        v = slink[v];
    }
    return z;
}
int main(){
    scanf("%s", ss);
    n = strlen(ss);
    int pre=1;
    for(int i=0; i<n; i++)
        pre = addChar(pre, ss[i]);
    for(int i=1; i<=tot; i++)
        cnt[slink[i]]++;
    for(int i=1; i<=tot; i++)
        if(!cnt[i])
            d.push(i);
    while(!d.empty()){
        int x=d.front();
        d.pop();
        cnt[slink[x]]--;
        cntendpos[slink[x]] += cntendpos[x];
        if(!cnt[slink[x]])  d.push(slink[x]);
    }
    for(int i=2; i<=tot; i++)
        ans[maxlen[i]] = max(ans[maxlen[i]], cntendpos[i]);
    for(int i=1; i<n; i++)
        ans[i] = max(ans[i], ans[i+1]);
    for(int i=1; i<=n; i++)
        printf("%d\n", ans[i]);
    return 0;
}

以上是关于后缀自动机学习笔记的主要内容,如果未能解决你的问题,请参考以下文章

学习笔记:python3,代码片段(2017)

学习笔记第十八节课

学习笔记:后缀数组

学习笔记 链接

html学习笔记

[OI笔记]后缀自动机