1.题目链接。求一个字符串本质不同的字串有多少个?本质不同定义为:两个字符串不相等。
2.这个问题其实十分的简单,从后缀数组的角度来看,对于每一个sa[i],我们知道sa[i]代表排名为i的这个后缀所在的位置,假设是j,那么这个后缀的长度就是n-j.他有n-j个前缀,这些前缀都是这个字符串的子串,可以证明(所有的子串都是可以从这些后缀的前缀产生,从数量上就可以证明,二者相等)。但是我们从高度数组的定义又可以看出来,height[i]表示lcp(sa[i],sa[i-1]),所以i和i-1又会有公共的前缀,这些是重复的,减去即可。那么这个题就十分的简单了,ans=sigma(n-sa[i]-heigh[i])。时间复杂度O(nlogn).
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int MAXN = 2e5 + 10;
int sa[MAXN], rnk[MAXN], rsort[MAXN], y[MAXN], wr[MAXN], height[MAXN];
char a[MAXN];
bool cmp(int a, int b, int len)
{
return wr[a] == wr[b] && wr[a + len] == wr[b + len];
}
void get_SA(int m, int n)
{
for (int i = 1; i <= n; i++) rnk[i] = a[i - 1];
for (int i = 1; i <= n; i++) rsort[rnk[i]]++;
for (int i = 1; i <= m; i++) rsort[i] += rsort[i - 1];
for (int i = n; i > 0; i--) sa[rsort[rnk[i]]--] = i;
int len = 1, p = 0;
while (p < n)
{
int k = 0;
//y[i]:以第二关键字排名,排名为i的第一关键字的位置
for (int i = n - len + 1; i <= n; i++) y[++k] = i;
for (int i = 1; i <= n; i++) if (sa[i] > len) y[++k] = sa[i] - len;
for (int i = 1; i <= n; i++) wr[i] = rnk[y[i]];
//wr[i]:以第二关键字排序,排名为i的第一关键字的排名
memset(rsort, 0, sizeof(rsort));
for (int i = 1; i <= n; i++) rsort[wr[i]]++;
for (int i = 1; i <= m; i++) rsort[i] += rsort[i - 1];
for (int i = n; i > 0; i--) sa[rsort[wr[i]]--] = y[i];
for (int i = 1; i <= n; i++) wr[i] = rnk[i];
p = 1; rnk[sa[1]] = 1;
for (int i = 2; i <= n; i++)
{
if (!cmp(sa[i], sa[i - 1], len)) p++;
rnk[sa[i]] = p;
}
m = p; len <<= 1;
}
}
void get_height(int n)
{
int k = 0, j;
for (int i = 1; i <= n; i++)
{
j = sa[rnk[i] - 1];
if (k) k--;
while (a[j + k - 1] == a[i + k - 1]) k++;
height[rnk[i]] = k;
}
}
ll solve(int n)
{
ll ans = 0;
for (int i = 1; i <= n; i++)
ans += n + 1 - sa[i] - height[i];
return ans;
}
int main()
{
int len;
scanf("%d", &len);
scanf("%s", a);
get_SA(300, len);
get_height(len);
printf("%lld", solve(len));
return 0;
}