社区讨论
从0开始的后缀数组为什么要在最后加$
P3809【模板】后缀排序参与者 5已保存回复 10
讨论操作
快速查看讨论及其快照的属性,并进行相关操作。
- 当前回复
- 10 条
- 当前快照
- 1 份
- 快照标识符
- @lo8b6ayx
- 此快照首次捕获于
- 2023/10/27 15:45 2 年前
- 此快照最后确认于
- 2025/02/08 15:05 去年
我的代码是在 @attack 题解的代码上改成下标从 开始的形式,然后通过了本题。
但是我在做别的题目的时候发现,如果输入中出现了连续3个以上的相同字母,如
aaa,这份代码就会段错误。但是我发现只要在最后加一个 $ 就能正常运行($ 是比所有字母的ascii码小的一个字符),这到底是为什么呢?我刚学后缀数组,这个问题直接给我整懵了,求大佬帮帮
CPP#include <bits/stdc++.h>
using namespace std;
const int Maxn = 1000000 + 10;
string str;
int n, m, len;
int sa[Maxn], rnk[Maxn], tp[Maxn], tax[Maxn];
// sa: 排名为 i 的后缀的位置
// rnk: 后缀 suffix[i] 的排名
// tp: 第二关键字排名为 i 的后缀的位置(基数排序用)
// tax: 元素 i 的出现次数(这里指的是排名),注意排名的出现次数是 n 级别的
int cnt = 0;
void print() {
printf("***************** %d \n", ++cnt);
printf(" "); for (int i = 0; i < n; i++) printf("%d ", i); printf("\n");
printf("sa "); for (int i = 0; i < n; i++) printf("%d ", sa[i]); printf("\n");
printf("rnk "); for (int i = 0; i < n; i++) printf("%d ", rnk[i]); printf("\n");
printf("tp "); for (int i = 0; i < n; i++) printf("%d ", tp[i]); printf("\n");
// printf("*****************\n");
}
void quick_sort() {
// print();
for(int i = 0; i < m; ++i) tax[i] = 0;
for(int i = 0; i < n; ++i) tax[rnk[i]]++;
for(int i = 1; i < m; ++i) tax[i] += tax[i - 1];
// tax 就是桶,做前缀和之后桶内数组的排名区间已知,只需要处理先后关系
for(int i = n - 1; i >= 0; --i) sa[--tax[rnk[tp[i]]]] = tp[i];
/* 在 quick_sort() 之前我们就已经将第二关键字按照大小关系排序了
* 从大到小枚举第二关键字,再用 rnk[i] 定位到第一关键字的大小
* tax[rnk[tp[i]]] 就表示当第一关键字相同时,第二关键字较大的这个后缀的排名是啥
*/
// print();
}
void suffix_sort() {
for(int i = 0; i < n; ++i) rnk[i] = str[i], tp[i] = i;
quick_sort();
for(int w = 1, p = 0; p + 1 < n; m = p + 1, w <<= 1) {
p = 0;
for(int i = n - w; i < n; ++i) tp[p++] = i;
// 这些后缀的第二关键字设置最小
for(int i = 0; i < n; ++i)
if(sa[i] >= w) tp[p++] = sa[i] - w;
// 比如第 i 位的第二关键字位置是 i + w,那么 sa[i] 自然就是 sa[i] - w 的第二关键字
// 显然对于 j < w,j 是不可能成为第二关键字的
// 而 sa 本来就是按照大小排序过的,所以只需要将 sa 数组复制给 tp
quick_sort();
swap(tp, rnk);
rnk[sa[0]] = p = 0;
for(int i = 1; i < n; ++i)
rnk[sa[i]] = (tp[sa[i - 1]] == tp[sa[i]] && tp[sa[i - 1] + w] == tp[sa[i] + w]) ? p : ++p;
// 本来应该 rnk[sa[i]] = i,但是相同的串应该是相同的排名
}
}
int main() {
#ifndef ONLINE_JUDGE
freopen("sample.in", "r", stdin);
freopen("output.out", "w", stdout);
ios::sync_with_stdio(false);
#endif
cin >> str; //str = str + '$';
n = str.length(); m = 0;
for(int i = 0; i < n; ++i) m = max(m, (int)str[i]);
++m;
suffix_sort();
for(int i = 0; i < n; ++i) cout << sa[i] + 1 << " ";
return 0;
}
回复
共 10 条回复,欢迎继续交流。
正在加载回复...