SP694
题目描述
求一个字符串本质不同的子串
题解
考虑容斥
因为每一个子串应该都是原串的一个后缀的前缀。因此重复的子串的总数应该就是所有后缀的
h
e
i
g
h
t
height
height数组的和。
a
n
s
=
n
∗
(
n
+
1
)
/
2
−
∑
i
=
1
n
h
e
i
g
h
t
[
i
]
ans=n*(n+1)/2-\sum_{i=1}^{n}height[i]
ans=n∗(n+1)/2−∑i=1nheight[i]
代码
#include<bits/stdc++.h>
#define M 1000009
#define int long long
using namespace std;
int n,tax[M],height[M],rk[M],sa[M],tp[M],m;
char s[M];
void Qsort(){
for(int i=0;i<=m;i++) tax[i]=0;
for(int i=1;i<=n;i++) tax[rk[i]]++;
for(int i=1;i<=m;i++) tax[i]+=tax[i-1];
for(int i=n;i>=1;i--) sa[tax[rk[tp[i]]]--]=tp[i];
}
void getheight(){
int k=0;
for(int i=1;i<=n;i++){
if(k) k--;
int j=sa[rk[i]-1];
while(s[i+k]==s[k+j]) k++;
height[rk[i]]=k;
}
}
void Suffix(){
n=strlen(s+1);m=127;
memset(sa,0,sizeof(sa));
for(int i=1;i<=n;i++) rk[i]=s[i],tp[i]=i;
Qsort();
for(int p=0,w=1;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,rk);
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-1]+w]==tp[sa[i]+w])?p:++p;
}getheight();
int res=n*(n+1)/2;;
for(int i=1;i<=n;i++)
res-=height[i];
printf("%lld\n",res);
}
signed main(){
int t;
scanf("%lld\n",&t);
for(int i=1;i<=t;i++){
scanf("%s",s+1);
Suffix();
}return 0;
}