int wa[N], wb[N], ws[N], wv[N]
int rank[N], height[N]
#此处N比输入的N要多1,为人工添加的一个字符,用于避免CMP时越界
void getSA(int *r, int *sa, int n, int m)
int i, j, p, *x = wa, *y = wb, *t
# bucket清空
for(i = 0; i < m; i++) ws[i] = 0
#进行一次基数排序
for(i = 0; i < n; i++) ws[x[i] = r[i]]++
for(i = 1; i < m; i++) ws[i] += ws[i - 1]
for(i = n - 1; i >= 0; i--) sa[--ws[x[i]]] = i
#倍增法
for(j = 1, p = 1; p < n; j *= 2, m = p)
#string[n - j .. n] 是没有偏移为j的后缀 故第二关键字默认为0
#所以按照第二关键字排序肯定在最前面 同时还需要保证稳定性
for(p = 0, i = n - j; i < n; i++) y[p++] = i
#SA定义为‘排第几的是谁‘ 根据第二关键字排序时
#第二关键字的次序就是其关联的第一关键字未完成排序时的次序
#所以SA[i] – j为按照第二关键字次序收集的未完成排序 的第一关键字序列
for(i = 0; i < n; i++) if(sa[i] >= j) y[p++] = sa[i] – j
#这里的x是临时的RANK数组 y是等待排序的第一关键字下标数组(即第i后缀)
#映射出第一关键字之间的相对大小
for(i = 0; i < n; i++) wv[i] = x[y[i]]
#bucket清空
for(i = 0; i < m; i++) ws[i] = 0
#进行一次基数排序
for(i = 0; i < n; i++) ws[wv[i]]++
for(i = 1; i < m; i++) ws[i] += ws[i - 1]
for(i = n - 1; i >= 0; i--) sa[--ws[wv[i]]] = y[i]
#交换x y重标号临时SA
for(t = x, x = y, y = t, p = 1, x[sa[0]] = 0, i = 1; i < n; i++)
x[sa[i]] = cmp(y, sa[i - 1], sa[i], j) ? p - 1 : p++
void getHeight(int *r, int *sa, int n)
int i, j, k = 0
#根据SA求RANK
for(i = 1; i <= n; i++) rank[sa[i]] = i
#利用性质 h[i] = height[rank[i]] 减少运算时间
#h[i] => height[rank[i]] => 表示第i后缀的height值
#第i后缀必然比第i-1后缀短 同时注意第i后缀 = 第i-1后缀剔除首字母
#记符号S(i)为原字符串的第i后缀
#记符号P(i)为第i后缀的SA值-1对应的后缀
#h[i] = height[rank[i]] => 第i后缀和第i后缀的SA值-1对应的后缀的LCP
#h[i-1] = height[rank[i-1]] => 第i-1后缀和第i-1后缀的SA值-1对应的后缀的LCP
#h[i] = LCP(S(i), P(i)) h[i - 1] = LCP(S(i - 1), P(i - 1))
#容易看出S(i - 1)剔除首字母后变为S(i)
#若h[i - 1] >= 1 则S(i - 1)和P(i - 1)的LCP >= 1
#P(i - 1)肯定是某个后缀 同时因为h[i - 1] >= 1 故strlen(P(i - 1)) >= 1
#所以P(i - 1)剔除首字母必然可以得到某个后缀
#同时由S(i - 1)剔除首字母可以得到S(i)和P(i)
#如果下标从1开始
#那么P(i - 1)和P(i)必然满足P(i - 1)[1 .. h[i - 1]] == P(i)[0 .. h[i - 1]]
#但P(i - 1)[h[i - 1] + 1 .. -1] 和 P(i)[h[i - 1] + 1 .. -1]不一定相等
#所以h[i] >= h[i - 1] - 1
#反之从0求h[i] 必然正确
#补充 height[i] = LCP(string[sa[i - 1] .. -1], string[sa[i] .. -1])
for(i = 0; i < n; height[rank[i++]] = k)
for(k ? k-- : 0, j = sa[rank[i] - 1]; r[i + k] == r[j + k]; k++)
char str[N]
int sa[N]
int main
char str[N]
scanf("%s", str)
int n = strlen(str)
str[n] = 0
#注意区分此处为n+1,因为添加了一个结尾字符用于区别比较
getSA(str, sa, n + 1, 128)
getHeight(str, sa, n)
时间: 2024-10-13 13:22:36