Solutions - SAM / 广义 SAM 的题
P4248 [AHOI2013] 差异
求一个定值减去所有后缀的 lcp 的和。
翻转以下序列可以转化成所有前缀的最长后缀,然后建出 SAM 在 parent 树上,对于每一个节点求它是多少对节点的 LCA 即可。
P3181 [HAOI2016] 找相同字符
求两个串的本质不同公共子串数量。
和上题差不多。公共子串等价于两串前缀的公共后缀,那么建广义 SAM 然后子树相乘即可。
#include <bits/stdc++.h>
#define llong long long
#define N 800005
using namespace std;
char a[N];
int pos[N], tag[N][3], son[N][32], trsiz = 1;
int fa[N], nxt[N][32], tsiz = 1;
int siz[N][3];
int len[N];
llong ans;
inline int insert(int ch, int lst, int in1, int in2){
int x = lst, cur = ++tsiz;
len[cur] = len[lst]+1;
siz[cur][1] += in1, siz[cur][2] += in2;
while(x && !nxt[x][ch])
nxt[x][ch] = cur, x = fa[x];
if(!x){
fa[cur] = 1;
return cur;
}
int y = nxt[x][ch];
if(len[y] == len[x]+1){
fa[cur] = y;
}
else{
int z = ++tsiz;
len[z] = len[x]+1;
fa[z] = fa[y];
for(int i = 1; i <= 26; ++i)
nxt[z][i] = nxt[y][i];
while(x && nxt[x][ch] == y)
nxt[x][ch] = z, x = fa[x];
fa[cur] = fa[y] = z;
}
return cur;
}
vector<int> G[N];
inline void dfs(int u){
for(int v : G[u]){
dfs(v);
siz[u][1] += siz[v][1];
siz[u][2] += siz[v][2];
}
ans += 1ll*(len[u]-len[fa[u]])*siz[u][1]*siz[u][2];
return;
}
int que[N], he, ta;
int main(){
for(int i = 1, l; i <= 2; ++i){
scanf("%s", a+1);
l = strlen(a+1);
int x = 1;
for(int j = 1; j <= l; ++j){
if(!son[x][a[j]^96]) son[x][a[j]^96] = ++trsiz;
x = son[x][a[j]^96];
++tag[x][i];
}
}
que[he = ta = 1] = 1;
pos[1] = 1;
while(he <= ta){
int x = que[he++];
for(int i = 1; i <= 26; ++i){
if(!son[x][i]) continue;
pos[son[x][i]] = insert(i, pos[x], tag[son[x][i]][1], tag[son[x][i]][2]);
que[++ta] = son[x][i];
}
}
for(int i = 1; i <= tsiz; ++i)
G[fa[i]].push_back(i);
dfs(1);
printf("%lld", ans);
return 0;
}
P8617 [蓝桥杯 2014 国 AC] 重复模式
找最长的出现次数不小于 \(2\) 的子串。
这不纯 SAM 板子吗。建出 SAM 然后在 parent 树上 dfs 求子树大小,如果子树不小于 \(2\) 就更新答案。
#include <bits/stdc++.h>
#define llong long long
#define N 1000006
using namespace std;
int n, ans;
char a[N];
int fa[N], nxt[N][32], tsiz = 1;
int len[N], siz[N];
inline int insert(int ch, int lst){
int x = lst, cur = ++tsiz;
len[cur] = len[lst]+1, siz[cur] = 1;
while(x && !nxt[x][ch])
nxt[x][ch] = cur, x = fa[x];
if(!x){
fa[cur] = 1;
return cur;
}
int y = nxt[x][ch];
if(len[y] == len[x]+1){
fa[cur] = y;
}
else{
int z = ++tsiz;
len[z] = len[x]+1;
fa[z] = fa[y];
for(int i = 1; i <= 26; ++i)
nxt[z][i] = nxt[y][i];
while(x && nxt[x][ch] == y)
nxt[x][ch] = z, x = fa[x];
fa[cur] = fa[y] = z;
}
return cur;
}
vector<int> G[N];
inline void dfs(int u){
for(int v : G[u]){
dfs(v);
siz[u] += siz[v];
}
if(siz[u] >= 2) ans = max(ans, len[u]);
return;
}
int main(){
scanf("%s", a+1);
n = strlen(a+1);
for(int i = 1, x = 1; i <= n; ++i)
x = insert(a[i]^96, x);
for(int i = 1; i <= tsiz; ++i)
G[fa[i]].push_back(i);
dfs(1);
printf("%d", ans);
return 0;
}

浙公网安备 33010602011771号