题意:
给一个字符串,统计字符串中不重复的子串个数。
做法:
后缀数组模板题。
观察到每一个子串都是一个后缀的前缀,重复的前缀就是sigma(h[i]),第i小的和第i-1小的后缀的lcp。
于是我们把ans减去sigma(h[i])就好了。
代码:
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<cstdlib>
#include<cctype>
using namespace std;
typedef long long LL;
const int N = 50010;
int n, m;
char a[N];
int rk[N], tp[N], SA[N], tong[N], h[N];
inline void js_sort()
{
for(int i = 0; i <= m; i ++) tong[i] = 0;
for(int i = 1; i <= n; i ++) tong[rk[tp[i]]] ++;
for(int i = 1; i <= m; i ++) tong[i] += tong[i-1];
for(int i = n; i >= 1; i --) SA[tong[rk[tp[i]]] --] = tp[i];
}
int main()
{
int Test; scanf("%d", &Test);
while(Test --) {
scanf("%s", a+1); n = strlen(a+1);
for(int i = 1; i <= n; i ++) { rk[i] = a[i]; tp[i] = i; }
m = 127; int p = 1, w = 1; js_sort();
while(p < n) {
p = 0;
for(int i = n-w+1; i <= n; i ++) tp[++ p] = i;
for(int i = 1; i <= n; i ++) if(SA[i] > w) tp[++ p] = SA[i]-w;
js_sort(); swap(rk, tp); rk[SA[1]] = p = 1;
for(int i = 2; i <= n; i ++) rk[SA[i]] = (tp[SA[i]] == tp[SA[i-1]] && tp[SA[i]+w] == tp[SA[i-1]+w]) ? p : ++ p;
w <<= 1; m = p;
}
int k = 0;
for(int i = 1; i <= n; i ++) {
if(k > 0) k --; int j = SA[rk[i]-1];
for(; a[i+k] == a[j+k]; k ++);
h[rk[i]] = k;
}
LL ans = 1LL*n*(n+1)/2;
for(int i = 1; i <= n; i ++) ans -= h[i];
printf("%lld\n", ans);
}
return 0;
}