后缀自动机(SAM) 合集

Posted hugh-locke

tags:

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

先上模板

技术图片
int len[maxn << 1],fa[maxn << 1],son[maxn << 1][maxc];
LL num[maxn << 1];
int size,last;
void Init()
    size = last = 1;

void insert(char c)
    int s = c - a;
    int p = last,np = ++size;last = np; num[np] = 1; //主链结点出现次数 + 1
    len[np] = len[p] + 1;
    for(;p && !son[p][s]; p = fa[p]) son[p][s] = np;
    if(!p) fa[np] = 1;
    else
        int q = son[p][s];
        if(len[p] + 1 == len[q]) fa[np] = q;
        else
            int nq = ++size; len[nq] = len[p] + 1;
            memcpy(son[nq],son[q],sizeof(son[q]));
            fa[nq] = fa[q]; fa[q] = fa[np] = nq;
            for(;son[p][s] == q && p;p = fa[p]) son[p][s] = nq;
        
    

void insert(char *s)
    Init();
    for(int i = 0; s[i] ; i ++) insert(s[i]);
View Code

 

9.10 update

P3804 【模板】后缀自动机

dfs parent树可以统计每个子串出现的次数

技术图片
#include <map>
#include <set>
#include <ctime>
#include <cmath>
#include <queue>
#include <stack>
#include <vector>
#include <string>
#include <bitset>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <sstream>
#include <iostream>
#include <algorithm>
#include <functional>
using namespace std;
#define For(i, x, y) for(int i=x;i<=y;i++)  
#define _For(i, x, y) for(int i=x;i>=y;i--)
#define Mem(f, x) memset(f,x,sizeof(f))  
#define Sca(x) scanf("%d", &x)
#define Sca2(x,y) scanf("%d%d",&x,&y)
#define Sca3(x,y,z) scanf("%d%d%d",&x,&y,&z)
#define Scl(x) scanf("%lld",&x)  
#define Pri(x) printf("%d\n", x)
#define Prl(x) printf("%lld\n",x)  
#define CLR(u) for(int i=0;i<=N;i++)u[i].clear();
#define LL long long
#define ULL unsigned long long  
#define mp make_pair
#define PII pair<int,int>
#define PIL pair<int,long long>
#define PLL pair<long long,long long>
#define pb push_back
#define fi first
#define se second 
typedef vector<int> VI;
int read()int x = 0,f = 1;char c = getchar();while (c<0 || c>9)if (c == -) f = -1;c = getchar();
while (c >= 0&&c <= 9)x = x * 10 + c - 0;c = getchar();return x*f;
const double PI = acos(-1.0);
const double eps = 1e-9;
const int maxn = 1e6 + 10;
const int maxc = 26;
const int INF = 0x3f3f3f3f;
const int mod = 1e9 + 7; 
int N,M,K;
int len[maxn << 1],fa[maxn << 1],son[maxn << 1][maxc];
LL num[maxn << 1];
int size,last;
void Init()
    size = last = 1;

void insert(char c)
    int s = c - a;
    int p = last,np = ++size;last = np; num[np] = 1; 
    len[np] = len[p] + 1;
    for(;p && !son[p][s]; p = fa[p]) son[p][s] = np;
    if(!p) fa[np] = 1;
    else
        int q = son[p][s];
        if(len[p] + 1 == len[q]) fa[np] = q;
        else
            int nq = ++size; len[nq] = len[p] + 1;
            memcpy(son[nq],son[q],sizeof(son[q]));
            fa[nq] = fa[q]; fa[q] = fa[np] = nq;
            for(;son[p][s] == q && p;p = fa[p]) son[p][s] = nq;
        
    

void insert(char *s)
    Init();
    for(int i = 0; s[i] ; i ++) insert(s[i]);

char str[maxn];
struct Edge
    int to,next;
edge[maxn << 1];
int head[maxn << 1],tot;
void init()
    for(int i = 0; i <= size; i ++) head[i] = -1;
    tot = 0;

void add(int u,int v)
    edge[tot].to = v;
    edge[tot].next = head[u];
    head[u] = tot++;

void dfs(int t)
    for(int i = head[t]; ~i ; i = edge[i].next)
        int v = edge[i].to;
        dfs(v);
        num[t] += num[v];
    

int main()
    scanf("%s",str);
    insert(str); init();
    for(int i = 2; i <= size; i ++) add(fa[i],i);
    dfs(1);
    LL ans = 0;
    for(int i = 2; i <= size; i ++) if(num[i] != 1)ans = max(ans,len[i] * num[i]);
    Prl(ans);
    return 0;
View Code

 

P1368 工艺

最小表示法,将原串倍增一遍插入,SAM上直接寻找长度为N的字典序最小的路径

因为是倍增了一遍,脑补证明往任意点出发必定能找到长度至少为N的路径,所以甚至不需要dfs,直接跑即可

技术图片
const int maxn = 6e5 + 10;
int N,M,K;
int len[maxn << 1],fa[maxn << 1];
map<int,int>son[maxn << 1];
int size,last;
void Init()
    size = last = 1;

inline void insert(int c)
    int p = last,np = ++size; last = np;
    len[np] = len[p] + 1;
    for(;p && !son[p].count(c); p = fa[p]) son[p][c] = np;
    if(!p) fa[np] = 1;
    else
        int q = son[p][c];
        if(len[p] + 1 == len[q]) fa[np] = q;
        else
            int nq = ++size; len[nq] = len[p] + 1;
            son[nq] = son[q];
            fa[nq] = fa[q]; fa[q] = fa[np] = nq;
            for(;son[p][c] == q && p; p = fa[p]) son[p][c] = nq;
        
    

int a[maxn];
int main()
    Sca(N); Init();
    for(int i = 1; i <= N ; i ++) insert(a[i] = read());
    for(int i = 1; i <= N ; i ++) insert(a[i]);
    int t = 1;
    for(int i = 1; i <= N ; i ++)
        printf("%d ",son[t].begin()->first);
        t = son[t].begin()->second;
    
    return 0;
View Code

 

K小子串

技术图片
#include <map>
#include <set>
#include <ctime>
#include <cmath>
#include <queue>
#include <stack>
#include <vector>
#include <string>
#include <bitset>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <sstream>
#include <iostream>
#include <algorithm>
#include <functional>
using namespace std;
#define For(i, x, y) for(int i=x;i<=y;i++)  
#define _For(i, x, y) for(int i=x;i>=y;i--)
#define Mem(f, x) memset(f,x,sizeof(f))  
#define Sca(x) scanf("%d", &x)
#define Sca2(x,y) scanf("%d%d",&x,&y)
#define Sca3(x,y,z) scanf("%d%d%d",&x,&y,&z)
#define Scl(x) scanf("%lld",&x)  
#define Pri(x) printf("%d\n", x)
#define Prl(x) printf("%lld\n",x)  
#define CLR(u) for(int i=0;i<=N;i++)u[i].clear();
#define LL long long
#define ULL unsigned long long  
#define mp make_pair
#define PII pair<int,int>
#define PIL pair<int,long long>
#define PLL pair<long long,long long>
#define pb push_back
#define fi first
#define se second 
typedef vector<int> VI;
int read()int x = 0,f = 1;char c = getchar();while (c<0 || c>9)if (c == -) f = -1;c = getchar();
while (c >= 0&&c <= 9)x = x * 10 + c - 0;c = getchar();return x*f;
const double PI = acos(-1.0);
const double eps = 1e-9;
const int maxn = 5e5 + 10;
const int maxc = 26;
const int INF = 0x3f3f3f3f;
const int mod = 1e9 + 7; 
int N,M,K;
int len[maxn << 1],fa[maxn << 1],son[maxn << 1][maxc];
int size,last;
int num[maxn << 1];
void Init()
    size = last = 1;

void insert(char c)
    int s = c - a;
    int p = last,np = ++size;last = np;num[np] = 1;
    len[np] = len[p] + 1;
    for(;p && !son[p][s]; p = fa[p]) son[p][s] = np;
    if(!p) fa[np] = 1;
    else
        int q = son[p][s];
        if(len[p] + 1 == len[q]) fa[np] = q;
        else
            int nq = ++size; len[nq] = len[p] + 1;
            memcpy(son[nq],son[q],sizeof(son[q]));
            fa[nq] = fa[q]; fa[q] = fa[np] = nq;
            for(;son[p][s] == q && p; p = fa[p]) son[p][s] = nq;
        
    

void insert(char *s)
    Init();
    for(int i = 0;s[i]; i ++) insert(s[i]);

char str[maxn];
int tmp[maxn << 1],A[maxn << 1];
int sum[maxn << 1];
void dfs(int t,int k)
    if(k <= num[t]) return;
    k -= num[t];
    for(int i = 0 ; i < 26; i ++)
        if(!son[t][i]) continue;
        int v = son[t][i];
        if(sum[v] >= k)
            printf("%c",i + a);
            dfs(v,k);
            return;
        
        k -= sum[v];
    

int main()
    scanf("%s",str); 
    insert(str); 
    for(int i = 1; i <= size; i ++) tmp[len[i]]++;
    for(int i = 1; i <= size; i ++) tmp[i] += tmp[i - 1];
    for(int i = 1; i <= size; i ++) A[tmp[len[i]]--] = i;
    for(int i = size; i >= 1; i --) num[fa[A[i]]] += num[A[i]];
    int op = read(),k = read();
    for(int i = 1; i <= size; i ++) sum[i] = op?num[i]:num[i] = 1;
    sum[1] = num[1] = 0;
    for(int i = size; i >= 1; i --)
        for(int j = 0 ; j < 26; j ++)
            if(son[A[i]][j]) sum[A[i]] += sum[son[A[i]][j]];
        
    
    if(sum[1] < k) puts("-1");
    else dfs(1,k);
    return 0;
View Code

 

留坑

以上是关于后缀自动机(SAM) 合集的主要内容,如果未能解决你的问题,请参考以下文章

模板后缀自动机 (SAM)

模板后缀自动机 (SAM)

SAM 后缀自动机

算法后缀自动机SAM

后缀自动机(SAM)模板

后缀自动机SAM