UVALive 6869(后缀数组)

传送门:Repeated Substrings

题意:给定一个字符串,求至少重复一次的不同子串个数。

分析:模拟写出子符串后缀并排好序可以发现,每次出现新的重复子串个数都是由现在的height值减去前一个height值。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
using namespace std;
const int maxn = ;
typedef long long LL;
int sa[maxn];
int t1[maxn], t2[maxn], c[maxn];
int ran[maxn], height[maxn];
int s[maxn];
char str[maxn]; void build_sa(int s[], int n, int m) {
int i, j, p, *x = t1, *y = t2;
for (i = ; i < m; i++) c[i] = ;
for (i = ; i < n; i++) c[x[i] = s[i]]++;
for (i = ; i < m; i++) c[i] += c[i-];
for (i = n-; i >= ; i--) sa[--c[x[i]]] = i; for (j = ; j <= n; j <<= ) {
p = ;
for (i = n-j; i < n; i++) y[p++] = i;
for (i = ; i < n; i++)
if (sa[i] >= j)
y[p++] = sa[i] - j;
for (i = ; i < m; i++) c[i] = ;
for (i = ; i < n; i++) c[x[y[i]]]++;
for (i = ; i < m; i++) c[i] += c[i-];
for (i = n-; i >= ; i--) sa[--c[x[y[i]]]] = y[i]; swap(x, y);
p = , x[sa[]] = ;
for (i = ; i < n; i++)
x[sa[i]] = y[sa[i-]] == y[sa[i]] && y[sa[i-]+j] == y[sa[i]+j] ? p- : p++; if (p >= n) break;
m = p;
}
} void getHeight(int s[],int n) {
int i, j, k = ;
for (i = ; i <= n; i++)
ran[sa[i]] = i;
for (i = ; i < n; i++) {
if (k) k--;
j = sa[ran[i]-];
while (s[i+k] == s[j+k]) k++;
height[ran[i]]=k;
}
}
int main() {
int T;
scanf("%d", &T);
while (T--) {
scanf("%s", str);
int n = strlen(str);
for (int i = ; i <= n; i++)
s[i] = str[i];
build_sa(s, n+, );
getHeight(s, n);
LL ans = ;
for (int i = ; i <= n; i++)
{
if(height[i]>height[i-])ans+=height[i]-height[i-];
}
printf("%lld\n", ans);
}
return ;
}
上一篇:【JavaScript】下大雪


下一篇:Java项目中使用Log4J