抱歉,您的浏览器无法访问本站
本页面需要浏览器支持(启用)JavaScript
了解详情 >

题面

传送门:SPOJ 694


Solution

这题可以用SAM来搞,也可以用SA来搞。但无论是哪种搞法,都是基本操作。下面我们来分别讲解一下怎么搞。

SAM

这题用SAM来求就十分粗暴简单。不会SAM的小伙伴可以戳这里 首先,我们先把SAM建出来。根据SAM的性质,我们从出发点随着SAM任意走,走到哪里都是一个完全不同的子串。因此,我们只需要对SAM做一个拓扑序DP/记忆化搜索即可求出SAM上的路径总数,既不同子串的数量。

SA

这题我们显然还是要把后缀数组和height建出来的,不会SA的小伙伴可以戳这里 我们可以发现,对于原串的一个后缀,它的每一个前缀都是原串中的子串。因此,如果我们把所有后缀长度加起来,得到的就是子串的总数量。 如何去重呢?我们可以发现任意两个后缀,它们会造成重复的子串一定是它们的公共前缀。因此,重复的子串的数量即为$\sum_{i=0}^nheight[i]$,答案既是后缀总长度减去重复子串的数量


Code

本题我用SA来实现,用SAM的小伙伴还请自行yy一下w。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int N=1000+10;
int id[N],sa[N],height[N];
long long rank[N];
void CountSort(long long a[],int n,int exp,int m)
{
static long long cnt[N],b[N];
memset(cnt,0,sizeof cnt);
for(int i=1;i<=n;i++)
cnt[(a[i]/exp)%m]++;
for(int i=1;i<=m;i++)
cnt[i]+=cnt[i-1];
for(int i=n;i>=1;i--)
{
b[cnt[(a[i]/exp)%m]]=a[i];
if(exp==1)
id[cnt[(a[i]/exp)%m]--]=i;
else
sa[cnt[(a[i]/exp)%m]--]=id[i];
}
for(int i=1;i<=n;i++)
a[i]=b[i];
}
void RadixSort(long long a[],int n,int m)
{
CountSort(a,n,1,m);
CountSort(a,n,m,m);
}
char s[N];
int n;
void GetSA()
{
static long long t[N];
for(int i=1;i<=n;i++)
rank[i]=t[i]=s[i];
int m=1000+1;
for(int k=1;;k=(k<<1))
{
for(int i=1;i<=n;i++)
rank[i]=t[i]=rank[i]*m+(i+k<=n?rank[i+k]:0);
RadixSort(t,n,m);
m=0;
for(int i=1;i<=n;i++)
{
if(t[i]!=t[i-1]) m++;
rank[sa[i]]=m;
}
if(m==n) break;
m++;
}

for(int i=1;i<=n;i++)
{
if(rank[i]==1) continue;
int to=max(0,height[rank[i-1]]-1);
for(;sa[rank[i]]+to<=n and sa[rank[i]-1]+to<=n;to++)
if(s[sa[rank[i]]+to]!=s[sa[rank[i]-1]+to])
break;
height[rank[i]]=to;
}
}
int main()
{
int T;
scanf("%d",&T);

for(;T>0;T--)
{
scanf("%s",s+1);

n=strlen(s+1);
memset(rank,0,sizeof rank);
GetSA();
long long ans=0;
for(int i=1;i<=n;i++)
ans+=n-sa[i]+1-height[i];

printf("%lld\n",ans);
}
return 0;
}

评论