后缀数组求不同子串的个数
如果学会后缀数组,那么这题就是一个对于后缀数组的结果的应用,具体看solve函数的注释
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <queue>
using namespace std;
const int N = 1e6 + 10;
const int INF = 0x3f3f3f3f;
struct SuffixArray {
///记住数组从1开始
/// SA后缀数组, rak排名, height
static const int MAXN = 1e6 + 10;
int N, M, rak[MAXN], sa[MAXN], tax[MAXN], tp[MAXN], Height[MAXN];
char s[MAXN];
void Qsort() {
for(int i = 0; i <= M; i++) tax[i] = 0;
for(int i = 1; i <= N; i++) tax[rak[i]]++;
for(int i = 1; i <= M; i++) tax[i] += tax[i - 1];
for(int i = N; i >= 1; i--) sa[ tax[rak[tp[i]]]-- ] = tp[i];
}
void SuffixSort() {
M = 300;
if(N == 0) N = strlen(s + 1);
for(int i = 1; i <= N; i++) rak[i] = s[i], tp[i] = i;
Qsort();
for(int w = 1, p = 0; p < N; M = p, w <<= 1) {
p = 0;
for(int i = 1; i <= w; i++) tp[++p] = N - w + i;
for(int i = 1; i <= N; i++) if(sa[i] > w) tp[++p] = sa[i] - w;
Qsort();
std::swap(tp, rak);
rak[sa[1]] = p = 1;
for(int i = 2; i <= N; i++)
rak[sa[i]] = (tp[sa[i - 1]] == tp[sa[i]] && tp[sa[i - 1] + w] == tp[sa[i] + w]) ? p : ++p;
}
}
void GetHeight() {
int j, k = 0;
for(int i = 1; i <= N; i++) {
if(k) k--;
int j = sa[rak[i] - 1];
while(s[i + k] == s[j + k]) k++;
Height[rak[i]] = k;
}
}
void debug() {
printf("id :");
for (int i = 1; i <= N; i++ ) printf("%-3d ", i); puts("");
printf("rank :");
for (int i = 1; i <= N; i++ ) printf("%-3d ", rak[i]); puts("");
printf("sa :");
for (int i = 1; i <= N; i++ ) printf("%-3d ", sa[i]); puts("");
printf("height:");
for (int i = 1; i <= N; i++ ) printf("%-3d ", Height[i]); puts("");
}
void solve() {
/**
给你一个长为N的字符串,求不同的子串的个数?
对于一个后缀sa[i],它产生了n-sa[i]个前缀,减去height[i]个相同的前缀(与前一个比较),
则产生了n-sa[i]-height[i]个子串。累加后即结果。
*/
long long ans = 0;
for(int i = 1; i <= N; i++ ) {
ans += N + 1 - sa[i] - Height[i];
}
cout << ans << endl;
}
} cwl;
int main() {
while(~scanf("%d", &cwl.N) && cwl.N) {
scanf("%s", cwl.s + 1);
cwl.SuffixSort();
cwl.GetHeight();
// cwl.debug();
cwl.solve();
}
return 0;
}