后缀自动机(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]);
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;
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;
#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;
留坑
以上是关于后缀自动机(SAM) 合集的主要内容,如果未能解决你的问题,请参考以下文章