CF1276F Asterisk Substrings [后缀自动机]
抄一下 \(\color{\black}{n}\color{\red}{antf}\) 的题解
我 nantf 怎么这么强啊…这题我不到半个小时就写掉了…为什么div1的时候只有一个人做掉这个 F 啊…这个不是我 nantf 随随便便就写掉的么…
这个 CF 评分 3300 的题为什么这么水啊,直接1A了(
我们先考虑不带 star 的,人人会做,\(\sum len_i - len_{fa_i}\)。
考虑 star 在最前面和最后面,最后一个字符插入到 SAM 之前统计一下 \(\sum len_i - len_{fa_i}\)。
然后考虑一下空字符和 star 字符,略。
考虑其他部分的答案,应该是以 \(i\) 为后缀的数量 \(\times\) \(i+2\) 为前缀的数量,这个挺好做的,下面讲一下。
我们在 \(i\) 对应的 \(sam\) 节点上插入 \(i+2\) 对应 \(rsam\) 的节点。
然后我们知道 \(fa_i\) 所对应的字符串是 \(i\) 的后缀,然后在 \(sam\) 上启发式合并,\(rsam\) 上面求个链并计算贡献,这题就没了。
对于我 nantf 来说代码不是特别好写么…所以丢这里好了
int n;
const int maxn = 4e5 + 54;
char s[maxn];
vector<int> g[maxn];
set<int> Real[maxn];
int Realsize[maxn], rt[maxn], rev[maxn];
int val[maxn], lg[maxn], dep[maxn];
int getmin(int x, int y) { return dep[x] < dep[y] ? x : y; }
int getpw(int x) { return 1 << x; }
struct mt {
vector<int> g[maxn];
int st[maxn][22], idx = 0;
int dfn[maxn], rev[maxn];
void dfs(int u) {
st[dfn[u] = ++idx][0] = u;
rev[dfn[u]] = u;
for (int v : g[u]) {
dfs(v);
st[++idx][0] = u;
}
}
int getlca(int x, int y) {
if (dfn[x] > dfn[y]) x ^= y ^= x ^= y;
x = dfn[x], y = dfn[y];
int t = lg[y - x + 1];
return getmin(st[x][t], st[y - getpw(t) + 1][t]);
}
} qwq;
int getdis(int x, int y) {
const int lca = qwq.getlca(x, y);
return dep[x] + dep[y] - 2 * dep[lca];
}
int ans = 0;
void insert(int v, int u) {
for (int t : Real[v]) {
if (Real[u].count(t)) {
continue;
} else {
auto it = Real[u].insert(t).fir;
auto l = it;
auto r = it;
if (l == Real[u].begin())
l = --Real[u].end();
else
--l;
++r;
if (r == Real[u].end()) r = Real[u].begin();
int a = qwq.rev[*l];
int b = qwq.rev[*r];
Realsize[u] += getdis(a, qwq.rev[t]) + getdis(b, qwq.rev[t]) - getdis(a, b);
}
}
Real[v].clear();
Realsize[v] = 0;
}
void dfs(int u) {
for (int v : g[u]) {
dfs(v);
if (sz(Real[rt[u]]) < sz(Real[rt[v]])) swap(rt[u], rt[v]);
insert(rt[v], rt[u]);
}
ans += (Realsize[rt[u]] >> 1) * val[u];
}
struct suffixautomaton {
int ch[maxn][26];
int cnt, las;
suffixautomaton() { cnt = las = 1; }
int len[maxn], fa[maxn];
void ins(int c) {
int p = las, np = las = ++cnt;
len[np] = len[p] + 1;
for (; p && !ch[p][c]; p = fa[p]) ch[p][c] = np;
if (!p) {
fa[np] = 1;
} else {
int q = ch[p][c];
if (len[q] == len[p] + 1) {
fa[np] = q;
} else {
int nq = ++cnt;
len[nq] = len[p] + 1;
memcpy(ch[nq], ch[q], sizeof(ch[q]));
fa[nq] = fa[q];
fa[q] = fa[np] = nq;
for (; p && ch[p][c] == q; p = fa[p]) ch[p][c] = nq;
}
}
}
void build1() {
rep(i, 2, cnt) g[fa[i]].pb(i);
rep(i, 1, cnt) rt[i] = i;
rep(i, 2, cnt) val[i] = len[i] - len[fa[i]];
int p = 1;
rep(i, 1, n - 2) {
int c = s[i] - 'a';
p = ch[p][c];
Real[p].insert(qwq.dfn[rev[i + 2]]);
Real[p].insert(qwq.dfn[1]);
Realsize[p] = dep[rev[i + 2]] * 2;
}
dfs(1);
}
void build2() {
rep(i, 2, cnt) { dep[i] = len[i], qwq.g[fa[i]].pb(i); }
qwq.dfs(1);
lg[1] = 0;
rep(i, 2, maxn - 1) { lg[i] = lg[i >> 1] + 1; }
rep(j, 1, 20) {
rep(i, 1, qwq.idx - getpw(j) + 1) qwq.st[i][j] =
getmin(qwq.st[i][j - 1], qwq.st[i + getpw(j - 1)][j - 1]);
}
}
int getcnt() {
int ans = 0;
rep(i, 2, cnt) ans += len[i] - len[fa[i]];
return ans;
}
} sam, rsam;
signed main() {
// code begin.
in >> (s + 1), n = strlen(s + 1);
rep(i, 1, n) {
if (i == n) ans += sam.getcnt();
sam.ins(s[i] - 'a');
}
Rep(i, n, 1) {
if (i == 1) ans += rsam.getcnt();
rsam.ins(s[i] - 'a');
rev[i] = rsam.las;
}
ans += sam.getcnt();
rsam.build2();
sam.build1();
++ans, ++ans;
out << ans << '\n';
return 0;
// code end.
}