存一个板子… 好难呀
题目是求一个字符串有多少中不同的字串.
char s[maxn];
int sa[maxn], t[maxn], t2[maxn], tt[maxn], c[maxn], ss[maxn];
int Rank[maxn], height[maxn];
bool cmp(int *r, int a, int b, int l) {
return r[a] == r[b] && r[a+l] == r[b+l];
}
// 名次数组:名次数组 Rank[i]保存的是 Suffix(i)在所有后缀中从小到大排列的“名次”。
/*后缀数组:后缀数组 SA 是一个一维数组,它保存 1..n 的某个排列 SA[1],
SA[2],......,SA[n],并且保证 Suffix(SA[i]) < Suffix(SA[i+1]),1≤i<n。
也就是将 S 的 n 个后缀从小到大进行排序之后把排好序的后缀的开头位置顺
次放入 SA 中。*/
//SA数组最后1-len代表的是所有的下标、SA[0]是添加的末尾
//height是1-len代表 定义 height[i]=suffix(sa[i-1])和 suffix(sa[i])的最长公共前缀,也就是排名相邻的两个后缀的最长公共前缀。
//一定要记住下标为0 的是添加的0,height和SA都是
void build_sa(int *r, int n, int m) {
int *x = t, *y = t2;
for (int i = 0; i < m; i++) c[i] = 0;
for (int i = 0; i < n; i++) c[x[i] = r[i]]++;
for (int i = 1; i < m; i++) c[i] += c[i-1];
for (int i = n - 1; i >= 0; i--) sa[--c[x[i]]] = i;
for (int j = 1; ; j <<= 1) {
int p = 0;
for (int i = n - j; i < n; i++) y[p++] = i;
for (int i = 0; i < n; i++) if (sa[i] >= j) y[p++] = sa[i] - j;
for (int i = 0; i < n; i++) tt[i] = x[y[i]];
for (int i = 0; i < m; i++) c[i] = 0;
for (int i = 0; i < n; i++) c[tt[i]]++;
for (int i = 1; i < m; i++) c[i] += c[i-1];
for (int i = n - 1; i >= 0; i--) sa[--c[tt[i]]] = y[i];
swap(x, y), p = 1, x[sa[0]] = 0;
for (int i = 1; i < n; i++)
x[sa[i]] = cmp(y, sa[i-1], sa[i], j) ? p - 1 : p++;
if (p >= n) break;
m = p;
}
}
void getHeight(int *r, int n) {
int k = 0;
for (int i = 1; i <= n; i++) Rank[sa[i]] = i;
for (int i = 0; i < n; i++) {
if (k) k--;
int j = sa[Rank[i] - 1];
while (r[i+k] == r[j+k]) k++;
height[Rank[i]] = k;
}
}
void solve() {
scanf("%s", s);
int len = strlen(s);
for (int i = 0; i < len; i++)
ss[i] = s[i];
ss[len] = 0; //使用ss代替s,并且在最后添加一个0构成 s + '0'
build_sa(ss, len+1, 256);
getHeight(ss, len);
ll ans = 0;
for (int i = 1 ; i <= len ; i ++) {
ans += len - sa[i] - height[i];
}
cout << ans << endl;
}