Loading

:D 获取中...

反正这个博客已经废弃了,那么随便发电也没事的吧

随便写写!!!!!!!!!!!!

假设读者已经知道 \(SA\)\(height\) 数组。定义 \(lcp(i, j)\) 为字符串以 \(i\) 为起点的后缀和以 \(j\) 为起点的后缀的最长公共前缀。

int lcp(int i, int j) {
	int l = rnk[i], r = rnk[j];
	if (l > r) swap(l, r);
	l++;
	int len = lg[r - l + 1];
	return min(f[l][len], f[r - (1 << len) + 1][len]);
}

最小表示法

设字符串 \(S\) 长度为 \(n\)。把 \(S\) 复制一份得到 \(S + S\),求出 \(SA\) 数组,第一个 \(\leq n\) 的位置就是开始的编号。\(\leq n\) 是为了保证合法。

子串查询

给出 \(T\),在线在 \(T\) 中找 \(S\)

子串是后缀的前缀。

那么求后缀数组,就是找以 \(S\) 开头的前缀。而且都以 \(S\) 开头,会排在一起,二分一波就可以找到出现位置 & 出现次数了。

处理连续的若干个相同子串

基本就是枚举这个子串的长度,然后根据相邻间隔的 LCP 和 LCS 计算贡献。LCS 可以把原串倒过来求 LCP。本质就是分别统计某个子串两边的字符串(所以一般要把自己算进去)。

如求重复次数最多的连续重复子串。比如针对 abbabaabaabab,枚举子串长度,到 \(3\) 的时候,假设相邻两点为 \(l = 4, r = 7\)。算 LCP:abaabaabababaabab,可以算到 abaaba,即两倍的子串;算 LCS:abbaaababba,可以算到 a。感性理解就是分别统计了两边。这里的话,答案就是 \(\max \{ \dfrac{lcs + lcp - 1}{len} \} + 1\),减去 \(1\) 是因为像上面的例子,如果符合条件,自身的那个字符应该是相等的,会被算一次;加上 \(1\) 是因为当前枚举的这个子串不会被统计。

并查集快速维护一类咸鱼卷

主要就是求出 \(ans_x = \sum\limits_{i = 1} ^ n \sum\limits_{j = i + 1} ^ n lcp(i, j) \geq x\)

答案肯定是单调的。所以倒过来加,因为只有加了一堆 \(height\) 之后总的 \(lcp\) 才会变小,可以用并查集维护这个过程。同时可以维护一些其它题目要求的信息。

本来可以写的再详细一点点,但是心力交瘁了 😦

为什么连 :( 都会渲染成 emoji 啊。

随便放个代码。

height[rnk[i]] = k;
v[k].push_back(rnk[i]);
// ...
for (int i = 1; i <= n; i++) fa[i] = i;
	for (int i = n - 1; ~i; i--)
		for (int j = 0; j < v[i].size(); j++) merge(s.sa[v[i][j]], s.sa[v[i][j] - 1]);
posted @ 2024-04-16 22:12  liuzimingc  阅读(19)  评论(0编辑  收藏  举报