SAM常解决的问题:
- 问题1.给定文本T,询问格式如下:给定字符串P,问P是否是T的子串。
- 问题2.给定字符串S,问它有多少不同的子串。(模板中的GetSubNum函数)
- 问题3.给定字符串S,求其所有不同子串的总长度。
- 问题4.给定字符串S,一系列询问——给出整数K_i,计算S的所有子串排序后的第K_i个。
- 问题5.给定字符串S,找到和它循环同构的字典序最小字符串。
- 问题.给定文本T,询问格式如下:给定字符串P,希望找出P作为子串在文本T中出现了多少次(出现区间可以相交)。
- 问题6.给定文本T,询问格式如下:给定字符串P,求P在文本中第一次出现的位置。
- 问题7.给定文本T,询问格式如下:给定字符串P,要求给出P在T中的所有出现位置(出现区间可以相交)。
- 问题8.给定两个字符串S和T。要求找出它们的最长公共子串,即一个字符串X,它同时是S和T的子串。
模板
#include<stdio.h>
#include<bits/stdc++.h>
#define maxc 28
using namespace std;
const int maxn = 1e6 + 5;
const int mod = 1e9 + 7;
typedef long long ll;
int len[maxn * 2],
link[maxn * 2],
cnt[maxn * 2],
nex[maxn * 2][maxc],
idx,
last;
ll epos[maxn * 2];
char str[maxn];
ll a[maxn];
void Iint() {
last = idx = 1;
link[1] = len[1] = 0;
}
void Extend(int c) {
int x = ++idx;
len[x] = len[last] + 1;
epos[x] = 1;
int p;
for (p = last; p && !nex[p][c]; p = link[p])nex[p][c] = x;
if (!p)link[x] = 1, cnt[1]++;
else {
int q = nex[p][c];
if (len[p] + 1 == len[q])
link[x] = q, cnt[q]++;
else {
int nq = ++idx;
len[nq] = len[p] + 1;
link[nq] = link[q];
memcpy(nex[nq], nex[q], sizeof(nex[q]));
for (; p&&nex[p][c] == q; p = link[p])
nex[p][c] = nq;
link[q] = link[x] = nq;
cnt[nq] += 2;
}
}
last = x;
}
void GetNpos() {
queue<int>q;
for (int i = 1; i <= idx; i++)
if (!cnt[i])q.push(i);
while (!q.empty()) {
int x = q.front();
q.pop();
epos[link[x]] += epos[x];
if (--cnt[link[x]] == 0)q.push(link[x]);
}
}
void GetSubNum() {
ll ans = 0;
for (int i = 2; i <= idx; i++)ans += len[i] - len[link[i]];
printf("%lld\n",ans);
}
void GetSubMax() {
GetNpos();
int n = strlen(str);
for (int i = 1; i <= idx; i++)a[len[i]] = max(a[len[i]], epos[i]);
for (int i = n - 1; i >= 1; i--)a[i] = max(a[i], a[i + 1]);
for (int i = 1; i <= n; i++)printf("%lld\n", a[i]);
}
int main() {
return 0;
}