后缀数组 杂题总结
前言
在阅读本文之前,请先确保你以了解一下东西的求法和定义:
-
,就是后缀字典序的排名。 -
,即 -
的一些基本作用,比如求 。
题外话,本人对于以上数组全部依靠哈希进行求解,所以复杂度会比正常人多一个二分的
其实是一道非常
首先,不难想到,把这个
具体来说,就是定义
同理,定义
显然,答案就是
其实,问题也就转化为了求
然后我们考虑如何进行统计。
显然有一个暴力枚举左右端点,然后
数据很水,小小优化一下也就是
我们考虑如何加速这个过程。
这里需要使用一个非常奇怪的
我们考虑枚举这个
然后每枚举一次,我们都在下标
可以发现,每个长度为
所以我们考虑去枚举这两个断点,然后看这两个断点对于答案的贡献。
显然,如果只是枚举的话,时间复杂度是
然后我们考虑算答案的贡献。
首先,对于一个合法的
然后假设这两个断点分别为
显然,如果
当然,更一般的,对于
对于
注意,由于我们算的只能是长度为
然后,由于是区间加
至于
但是实际上,哈希比后缀数组快得多,不知道为什么。
#include <bits/stdc++.h>
using namespace std;
#define maxn 30005
#define ull unsigned long long
int t;
char a[maxn];
int n;
int f[maxn], g[maxn];
ull Has[maxn], p[maxn];
ull get(int l, int r)
{
return Has[l] - Has[r + 1] * p[r - l + 1];
}
int main()
{
scanf("%d", &t);
while(t--)
{
scanf("%s", a + 1);
n = strlen(a + 1);
memset(f, 0, sizeof(f));
memset(g, 0, sizeof(g));
p[0] = 1, Has[n + 1] = 0;
for (int i = n; i >= 1; --i) Has[i] = Has[i + 1] * 173 + a[i];
for (int i = 1; i <= n; ++i) p[i] = p[i - 1] * 173;
for (int len = 1; len * 2 <= n; ++len)
{
for (int i = len * 2; i <= n; i += len)
{
if(a[i] != a[i - len]) continue;
int last = i - len;
int L, R;
int l = 1, r = len, mid, ans = 0;
while(l <= r)
{
mid = (l + r) >> 1;
if(get(last - mid + 1, last) == get(i - mid + 1, i)) l = mid + 1, ans = mid;
else r = mid - 1;
}
L = i - ans + 1, L = max(L + len - 1, i);
l = 1, r = len, ans = 0;
while(l <= r)
{
mid = (l + r) >> 1;
if(get(last, last + mid - 1) == get(i, i + mid - 1)) l = mid + 1, ans = mid;
else r = mid - 1;
}
R = i + ans - 1, R = min(R, i + len - 1);
if(L <= R)
{
f[L - len * 2 + 1]++, f[R - len * 2 + 2]--;
g[L]++, g[R + 1]--;
}
}
}
for (int i = 1; i <= n; ++i) f[i] += f[i - 1], g[i] += g[i - 1];
long long ans = 0;
for (int i = 1; i <= n; ++i) ans += g[i] * 1ll * f[i + 1];
cout << ans << endl;
}
}
其实是对上面那个分段点技巧的一个应用,不过这道题感觉思维难度明显更高。
对于一个重复次数大于
故,对于原串中的位置
但是显然,我们不可能既去枚举
根据上一道题的思路,我们考虑去枚举这个
其实也很简单,对于前面的贡献,其实也就是
故对于相邻的两个断点,
最后求一个
时间复杂度的分析同上。
#include <bits/stdc++.h>
using namespace std;
#define maxn 300005
const int mod = 998344353;
int t;
char a[maxn];
int n;
int Has[maxn], p[maxn];
int get(int l, int r)
{
return ((Has[r] - 1ll * Has[l - 1] * p[r - l + 1] % mod) % mod + mod) % mod;
}
int main()
{
scanf("%d", &n);
for (int i = 1; i <= n; ++i) cin >> a[i];
p[0] = 1, Has[0] = 0;
for (int i = 1; i <= n; ++i) Has[i] = (Has[i - 1] * 173ll + a[i]) % mod;
for (int i = 1; i <= n; ++i) p[i] = (p[i - 1] * 173ll) % mod;
int sum = 0;
for (int len = 1; len <= n; ++len)
{
for (int i = len + 1; i <= n; i += len)
{
int last = i - len;
if(a[i] != a[last]) continue;
int L, R;
int l = 1, r = last, mid, ans = 0;
while(l <= r)
{
mid = (l + r) >> 1;
if(get(last - mid + 1, last) == get(i - mid + 1, i)) l = mid + 1, ans = mid;
else r = mid - 1;
}
L = ans;
l = 1, r = n - i + 1, ans = 0;
while(l <= r)
{
mid = (l + r) >> 1;
if(get(last, last + mid - 1) == get(i, i + mid - 1)) l = mid + 1, ans = mid;
else r = mid - 1;
}
R = ans;
sum = max((L + R - 1) / len + 1, sum);
}
}
cout << sum << endl;
}
一道将
我们先抛开第二小问不谈,其实就是让你求
有一个显然的思路,就是先通过后缀数组维护得到
你可以得到
我们需要考虑加速这个过程。
我们发现一个有趣的事情,当我们在求
那就非常简单了。
我们可以考虑倒着枚举
用并查集维护
至于最值,由于存在负数,考虑分别对一个集合求出
除开后缀数组,时间复杂度
#include <bits/stdc++.h>
using namespace std;
#define maxn 1000005
const int mod = 998244353;
char a[maxn];
int n;
int val[maxn];
int sa[maxn];
int Has[maxn], p[maxn];
int get(int l, int r)
{
return ((Has[r] - 1ll * Has[l - 1] * p[r - l + 1] % mod) % mod + mod) % mod;
}
int lcp(int x, int y)
{
int l = 1, r = min(n - x, n - y) + 1, mid, ans = 0;
while(l <= r)
{
int mid = (l + r) >> 1;
if(get(x, x + mid - 1) == get(y, y + mid - 1)) l = mid + 1, ans = mid;
else r = mid - 1;
}
return ans;
}
bool cmp(int x, int y)
{
if(a[x] != a[y]) return a[x] < a[y];
if(a[x + 1] != a[y + 1]) return a[x + 1] < a[y + 1];
if(a[x + 2] != a[y + 2]) return a[x + 2] < a[y + 2];
if(a[x + 3] != a[y + 3]) return a[x + 3] < a[y + 3];
if(a[x + 4] != a[y + 4]) return a[x + 4] < a[y + 4];
int l = 1, r = min(n - x + 1, n - y + 1), mid, ans;
while(l <= r)
{
mid = (l + r) >> 1;
if(get(x, x + mid - 1) == get(y, y + mid - 1)) ans = mid, l = mid + 1;
else r = mid - 1;
}
return a[ans + x] < a[ans + y];
}
int height[maxn];
int fa[maxn], siz[maxn];
long long maxx[maxn], minn[maxn], ans[maxn], sum[maxn];
long long nowsum, nowans;
int findroot(int x)
{
if(fa[x] == x) return x;
return fa[x] = findroot(fa[x]);
}
void unionn(int x, int y)
{
int p = findroot(x), q = findroot(y);
if(p == q) return;
nowsum += 1ll * siz[p] * siz[q], nowans = max(nowans, max(maxx[p] * maxx[q], minn[q] * minn[p]));
fa[q] = p, siz[p] += siz[q];
maxx[p] = max(maxx[p], maxx[q]), minn[p] = min(minn[p], minn[q]);
}
vector<int> id[maxn];
int main()
{
scanf("%d", &n);
scanf("%s", a + 1);
for (int i = 1; i <= n; ++i) scanf("%d", &val[i]);
p[0] = 1, Has[0] = 0;
for (int i = 1; i <= n; ++i) sa[i] = i, Has[i] = (Has[i - 1] * 173ll + a[i]) % mod;
for (int i = 1; i <= n; ++i) p[i] = (p[i - 1] * 173ll) % mod;
stable_sort(sa + 1, sa + n + 1, cmp);
for (int i = 2; i <= n; ++i) height[i] = lcp(sa[i], sa[i - 1]), id[height[i]].push_back(i);
id[0].push_back(1);
for (int i = 1; i <= n; ++i) fa[i] = i, siz[i] = 1, minn[i] = maxx[i] = val[sa[i]];
nowans = 0xf3f3f3f3f3f3f3f3;
for (int i = n - 1; i >= 0; --i)
{
for (int j = 0; j < id[i].size(); ++j) unionn(id[i][j], id[i][j] - 1);
ans[i] = nowsum, sum[i] = nowans;
}
for (int i = 0; i < n; ++i)
{
if(sum[i] == 0xf3f3f3f3f3f3f3f3) sum[i] = 0;
printf("%lld %lld\n", ans[i], sum[i]);
}
return 0;
}
可以考虑直接套用上一题的
通过差分,我们可以得到
首先,对于题目中的
然后我们只需要考虑算出
咱就是说,这不就是
分别计算,然后减去即可,时间复杂度同上。
当然,这样做其实有一点大财小用,完全可以直接用单调队列来解决。
#include <bits/stdc++.h>
using namespace std;
#define maxn 1000005
const int mod = 998244853;
char a[maxn];
int n;
int val[maxn];
int sa[maxn];
int Has[maxn], p[maxn];
int get(int l, int r)
{
return ((Has[r] - 1ll * Has[l - 1] * p[r - l + 1] % mod) % mod + mod) % mod;
}
int lcp(int x, int y)
{
int l = 1, r = min(n - x, n - y) + 1, mid, ans = 0;
while(l <= r)
{
int mid = (l + r) >> 1;
if(get(x, x + mid - 1) == get(y, y + mid - 1)) l = mid + 1, ans = mid;
else r = mid - 1;
}
return ans;
}
bool cmp(int x, int y)
{
if(a[x] != a[y]) return a[x] < a[y];
if(a[x + 1] != a[y + 1]) return a[x + 1] < a[y + 1];
if(a[x + 2] != a[y + 2]) return a[x + 2] < a[y + 2];
if(a[x + 3] != a[y + 3]) return a[x + 3] < a[y + 3];
if(a[x + 4] != a[y + 4]) return a[x + 4] < a[y + 4];
if(a[x + 5] != a[y + 5]) return a[x + 5] < a[y + 5];
if(a[x + 6] != a[y + 6]) return a[x + 6] < a[y + 6];
if(a[x + 7] != a[y + 7]) return a[x + 7] < a[y + 7];
if(a[x + 8] != a[y + 8]) return a[x + 8] < a[y + 8];
if(a[x + 9] != a[y + 9]) return a[x + 9] < a[y + 9];
if(a[x + 10] != a[y + 10]) return a[x + 10] < a[y + 10];
if(a[x + 11] != a[y + 11]) return a[x + 11] < a[y + 11];
if(a[x + 12] != a[y + 12]) return a[x + 12] < a[y + 12];
if(a[x + 13] != a[y + 13]) return a[x + 13] < a[y + 13];
if(a[x + 14] != a[y + 14]) return a[x + 14] < a[y + 14];
if(a[x + 15] != a[y + 15]) return a[x + 15] < a[y + 15];
int l = 1, r = min(n - x + 1, n - y + 1), mid, ans;
while(l <= r)
{
mid = (l + r) >> 1;
if(get(x, x + mid - 1) == get(y, y + mid - 1)) ans = mid, l = mid + 1;
else r = mid - 1;
}
return a[ans + x] < a[ans + y];
}
int height[maxn];
int fa[maxn], siz[maxn];
long long ans[maxn];
long long nowsum, sum;
int findroot(int x)
{
if(fa[x] == x) return x;
return fa[x] = findroot(fa[x]);
}
void unionn(int x, int y)
{
int p = findroot(x), q = findroot(y);
nowsum += 1ll * siz[p] * siz[q];
fa[q] = p, siz[p] += siz[q];
}
vector<int> id[maxn];
int main()
{
scanf("%s", a + 1);
n = strlen(a + 1);
for (int i = 1; i <= n; ++i) sum += 1ll * (n - i + 1) * (n - 1);
p[0] = 1, Has[0] = 0;
for (int i = 1; i <= n; ++i) sa[i] = i, Has[i] = (Has[i - 1] * 1331ll + a[i]) % mod;
for (int i = 1; i <= n; ++i) p[i] = (p[i - 1] * 1331ll) % mod;
stable_sort(sa + 1, sa + n + 1, cmp);
for (int i = 2; i <= n; ++i) height[i] = lcp(sa[i], sa[i - 1]), id[height[i]].push_back(i);
id[0].push_back(1);
for (int i = 1; i <= n; ++i) fa[i] = i, siz[i] = 1;
for (int i = n - 1; i >= 0; --i)
{
for (int j = 0; j < id[i].size(); ++j) unionn(id[i][j], id[i][j] - 1);
ans[i] = nowsum;
}
for (int i = 0; i <= n - 1; ++i) ans[i] -= ans[i + 1], sum -= 2ll * i * ans[i];
cout << sum << endl;
return 0;
}
其实,本质上也是求
显然是将
然后我们考虑如何计算答案。
其实也是一样的。
我们考虑根据上面两个题目的思路,在并查集合并的时候,将
需要注意的一点是,我们算要出的这个长度是用
故,我们考虑对每一个集合分别维护
那么在合并的时候,我们只需要让答案加上
时间复杂度同上。
#include <bits/stdc++.h>
using namespace std;
#define maxn 1000005
const int mod = 998244853;
char a[maxn], b[maxn];
int n, m;
int val[maxn];
int sa[maxn];
unsigned long long Has[maxn], p[maxn];
unsigned long long get(int l, int r)
{
return Has[r] - Has[l - 1] * p[r - l + 1];
}
int lcp(int x, int y)
{
int l = 1, r = min(n - x, n - y) + 1, mid, ans = 0;
while(l <= r)
{
int mid = (l + r) >> 1;
if(get(x, x + mid - 1) == get(y, y + mid - 1)) l = mid + 1, ans = mid;
else r = mid - 1;
}
return ans;
}
bool cmp(int x, int y)
{
if(a[x] != a[y]) return a[x] < a[y];
if(a[x + 1] != a[y + 1]) return a[x + 1] < a[y + 1];
if(a[x + 2] != a[y + 2]) return a[x + 2] < a[y + 2];
if(a[x + 3] != a[y + 3]) return a[x + 3] < a[y + 3];
if(a[x + 4] != a[y + 4]) return a[x + 4] < a[y + 4];
if(a[x + 5] != a[y + 5]) return a[x + 5] < a[y + 5];
if(a[x + 6] != a[y + 6]) return a[x + 6] < a[y + 6];
if(a[x + 7] != a[y + 7]) return a[x + 7] < a[y + 7];
if(a[x + 8] != a[y + 8]) return a[x + 8] < a[y + 8];
if(a[x + 9] != a[y + 9]) return a[x + 9] < a[y + 9];
if(a[x + 10] != a[y + 10]) return a[x + 10] < a[y + 10];
if(a[x + 11] != a[y + 11]) return a[x + 11] < a[y + 11];
if(a[x + 12] != a[y + 12]) return a[x + 12] < a[y + 12];
if(a[x + 13] != a[y + 13]) return a[x + 13] < a[y + 13];
if(a[x + 14] != a[y + 14]) return a[x + 14] < a[y + 14];
if(a[x + 15] != a[y + 15]) return a[x + 15] < a[y + 15];
int l = 15, r = min(n - x + 1, n - y + 1), mid, ans;
while(l <= r)
{
mid = (l + r) >> 1;
if(get(x, x + mid - 1) == get(y, y + mid - 1)) ans = mid, l = mid + 1;
else r = mid - 1;
}
return a[ans + x] < a[ans + y];
}
int height[maxn];
int fa[maxn], siz1[maxn], siz2[maxn];
long long ans[maxn];
long long nowsum, sum;
int findroot(int x)
{
if(fa[x] == x) return x;
return fa[x] = findroot(fa[x]);
}
void unionn(int x, int y)
{
int p = findroot(x), q = findroot(y);
if(siz1[p] + siz2[p] < siz1[q] + siz2[q]) swap(p, q);
nowsum += 1ll * siz1[p] * siz2[q];
nowsum += 1ll * siz2[p] * siz1[q];
fa[q] = p, siz1[p] += siz1[q], siz2[p] += siz2[q];
}
vector<int> id[maxn];
int main()
{
scanf("%s", a + 1);
a[(int)strlen(a + 1) + 1] = '.';
scanf("%s", b + 1);
n = strlen(a + 1), m = strlen(b + 1);
for (int i = n + 1; i <= n + m; ++i) a[i] = b[i - n];
n += m;
m = n - m;
p[0] = 1, Has[0] = 0;
for (int i = 1; i <= n; ++i) sa[i] = i, Has[i] = Has[i - 1] * 137 + a[i], p[i] = p[i - 1] * 137;
cerr << "qwq" << endl;
stable_sort(sa + 1, sa + n + 1, cmp);
for (int i = 2; i <= n; ++i) height[i] = lcp(sa[i], sa[i - 1]), id[height[i]].push_back(i);
id[0].push_back(1);
for (int i = 1; i <= n; ++i) fa[i] = i, siz1[i] = (sa[i] <= m), siz2[i] = (sa[i] > m);
for (int i = n - 1; i >= 0; --i)
{
for (int j = 0; j < id[i].size(); ++j) unionn(id[i][j], id[i][j] - 1);
ans[i] = nowsum;
}
for (int i = 0; i <= n - 1; ++i) ans[i] -= ans[i + 1], sum += i * 1ll * ans[i];
cout << sum << endl;
return 0;
}
首先破环为链,在原字符串后面再复制一遍,然后跑后缀数组。
显然,此时已经排好序了,直接从
没什么好说的,不过就是一个正常的破环为链的技巧。
#include <bits/stdc++.h>
using namespace std;
#define maxn 1000005
const int mod = 998244853;
char a[maxn], b[maxn];
int n, m;
int val[maxn];
int sa[maxn];
unsigned long long Has[maxn], p[maxn];
unsigned long long get(int l, int r)
{
return Has[r] - Has[l - 1] * p[r - l + 1];
}
int lcp(int x, int y)
{
int l = 1, r = min(n - x, n - y) + 1, mid, ans = 0;
while(l <= r)
{
int mid = (l + r) >> 1;
if(get(x, x + mid - 1) == get(y, y + mid - 1)) l = mid + 1, ans = mid;
else r = mid - 1;
}
return ans;
}
bool cmp(int x, int y)
{
if(a[x] != a[y]) return a[x] < a[y];
if(a[x + 1] != a[y + 1]) return a[x + 1] < a[y + 1];
if(a[x + 2] != a[y + 2]) return a[x + 2] < a[y + 2];
if(a[x + 3] != a[y + 3]) return a[x + 3] < a[y + 3];
if(a[x + 4] != a[y + 4]) return a[x + 4] < a[y + 4];
if(a[x + 5] != a[y + 5]) return a[x + 5] < a[y + 5];
if(a[x + 6] != a[y + 6]) return a[x + 6] < a[y + 6];
if(a[x + 7] != a[y + 7]) return a[x + 7] < a[y + 7];
if(a[x + 8] != a[y + 8]) return a[x + 8] < a[y + 8];
if(a[x + 9] != a[y + 9]) return a[x + 9] < a[y + 9];
if(a[x + 10] != a[y + 10]) return a[x + 10] < a[y + 10];
if(a[x + 11] != a[y + 11]) return a[x + 11] < a[y + 11];
if(a[x + 12] != a[y + 12]) return a[x + 12] < a[y + 12];
if(a[x + 13] != a[y + 13]) return a[x + 13] < a[y + 13];
if(a[x + 14] != a[y + 14]) return a[x + 14] < a[y + 14];
if(a[x + 15] != a[y + 15]) return a[x + 15] < a[y + 15];
int l = 15, r = min(n - x + 1, n - y + 1), mid, ans;
while(l <= r)
{
mid = (l + r) >> 1;
if(get(x, x + mid - 1) == get(y, y + mid - 1)) ans = mid, l = mid + 1;
else r = mid - 1;
}
return a[ans + x] < a[ans + y];
}
int main()
{
scanf("%s", a + 1);
n = strlen(a + 1);
for (int i = n + 1; i <= n + n; ++i) a[i] = a[i - n];
n += n;
p[0] = 1, Has[0] = 0;
for (int i = 1; i <= n; ++i) sa[i] = i, Has[i] = Has[i - 1] * 137 + a[i], p[i] = p[i - 1] * 137;
stable_sort(sa + 1, sa + n + 1, cmp);
for (int i = 1; i <= n; ++i)
{
if(sa[i] > n / 2) continue;
printf("%c", a[sa[i] + n / 2 - 1]);
}
puts("");
return 0;
}
首先,字符串里面没有
然后先破环为链,把字符串直接复制一遍。
然后我们考虑一个二分,因为所有长度为定值的字符串必然可以在后缀数组得到的排名中一一对应,故我们直接二分其在后缀数组的排名。
接着为了方便,我们令
首先先思考一个比较劣的对于
不难想到枚举一个起始点,然后向后匹配
对于每次匹配,假设当前枚举到
我们看能否有一个起始点匹配长度到
但是你每次尽可能多的匹配
但其实本质上,你从
故这个尽可能多的匹配的策略是正确的。
至于那个起始点,经过思考,其实你只需要枚举
#include <bits/stdc++.h>
using namespace std;
#define maxn 1000005
const int mod = 998244853;
char a[maxn], b[maxn];
int n, m, len;
int val[maxn];
int sa[maxn], rnk[maxn];
unsigned long long Has[maxn], p[maxn];
unsigned long long get(int l, int r)
{
return Has[r] - Has[l - 1] * p[r - l + 1];
}
int lcp(int x, int y)
{
int l = 1, r = min(n - x, n - y) + 1, mid, ans = 0;
while(l <= r)
{
int mid = (l + r) >> 1;
if(get(x, x + mid - 1) == get(y, y + mid - 1)) l = mid + 1, ans = mid;
else r = mid - 1;
}
return ans;
}
bool cmp(int x, int y)
{
if(a[x] != a[y]) return a[x] < a[y];
if(a[x + 1] != a[y + 1]) return a[x + 1] < a[y + 1];
if(a[x + 2] != a[y + 2]) return a[x + 2] < a[y + 2];
if(a[x + 3] != a[y + 3]) return a[x + 3] < a[y + 3];
if(a[x + 4] != a[y + 4]) return a[x + 4] < a[y + 4];
if(a[x + 5] != a[y + 5]) return a[x + 5] < a[y + 5];
if(a[x + 6] != a[y + 6]) return a[x + 6] < a[y + 6];
if(a[x + 7] != a[y + 7]) return a[x + 7] < a[y + 7];
if(a[x + 8] != a[y + 8]) return a[x + 8] < a[y + 8];
if(a[x + 9] != a[y + 9]) return a[x + 9] < a[y + 9];
if(a[x + 10] != a[y + 10]) return a[x + 10] < a[y + 10];
if(a[x + 11] != a[y + 11]) return a[x + 11] < a[y + 11];
if(a[x + 12] != a[y + 12]) return a[x + 12] < a[y + 12];
if(a[x + 13] != a[y + 13]) return a[x + 13] < a[y + 13];
if(a[x + 14] != a[y + 14]) return a[x + 14] < a[y + 14];
if(a[x + 15] != a[y + 15]) return a[x + 15] < a[y + 15];
int l = 15, r = min(n - x + 1, n - y + 1), mid, ans;
while(l <= r)
{
mid = (l + r) >> 1;
if(get(x, x + mid - 1) == get(y, y + mid - 1)) ans = mid, l = mid + 1;
else r = mid - 1;
}
return a[ans + x] < a[ans + y];
}
bool check(int mid)
{
for (int i = 1; i <= len; ++i)
{
int id = i;
for (int j = 1; j <= m; ++j)
{
if(rnk[id] > mid) id += len - 1;
else id += len;
}
if(id - i >= n / 2) return true;
}
return false;
}
int main()
{
scanf("%d %d", &n, &m);
len = ceil(n / (m * 1.0));
scanf("%s", a + 1);
for (int i = n + 1; i <= n + n; ++i) a[i] = a[i - n];
n += n;
p[0] = 1, Has[0] = 0;
for (int i = 1; i <= n; ++i) sa[i] = i, Has[i] = Has[i - 1] * 137 + a[i], p[i] = p[i - 1] * 137;
stable_sort(sa + 1, sa + n + 1, cmp);
for (int i = 1; i <= n; ++i) rnk[sa[i]] = i;
int l = 0, r = n, mid, ans = 0;
while(l <= r)
{
mid = (l + r) >> 1;
if(check(mid)) ans = mid, r = mid - 1;
else l = mid + 1;
}
int id = 0;
for (int i = 1; i <= n / 2; ++i) if(rnk[i] == ans)
{
id = i;
break;
}
for (int i = id; i <= id + len - 1; ++i) putchar(a[i]);
return 0;
}
后记
总的来说,其实后缀数组的题目本质上分为一下三类:
-
通过确定需要的字符串的长度(无论是去直接枚举,还是二分),然后通过相邻的两个断点,结算得到其对于答案的贡献,注意不要算重。
-
通过对
数组,使用数据结构进行维护,达到你要求的答案的目的。 -
通过将一段后缀转化为排名,更好的去储存或者遍历字符串,方便操作(比如第七题的二分)。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探