两侧同时换到之前的修订记录 前一修订版 后一修订版 | 前一修订版 | ||
2020-2021:teams:legal_string:jxm2001:字符串_3 [2020/08/31 13:02] jxm2001 |
2020-2021:teams:legal_string:jxm2001:字符串_3 [2020/09/02 10:52] (当前版本) jxm2001 |
||
---|---|---|---|
行 1: | 行 1: | ||
====== 字符串 3 ====== | ====== 字符串 3 ====== | ||
- | ===== 后缀数组 ===== | + | ===== 后缀数组(SA) ===== |
==== 算法简介 ==== | ==== 算法简介 ==== | ||
行 41: | 行 41: | ||
<code cpp> | <code cpp> | ||
namespace SA{ | namespace SA{ | ||
- | int sa[MAXN],rk[MAXN],height[MAXN],x[MAXN],y[MAXN],c[MAXN]; | + | int sa[MAXN],rk[MAXN],height[MAXN],X[MAXN],Y[MAXN],c[MAXN]; |
int d[MAXN][MAXM],lg2[MAXN]; | int d[MAXN][MAXM],lg2[MAXN]; | ||
void get_sa(char *s,int n,int m){//s下标从1开始 | void get_sa(char *s,int n,int m){//s下标从1开始 | ||
+ | int *x=X,*y=Y; | ||
_rep(i,0,m)c[i]=0; | _rep(i,0,m)c[i]=0; | ||
_rep(i,1,n)c[x[i]=s[i]]++; | _rep(i,1,n)c[x[i]=s[i]]++; | ||
行 588: | 行 589: | ||
于是 $\text{dp}_i=\sum_{1\le j\lt i}\text{LCP}(T_i,T_j)=\text{dp}_j+(i-j)\text{height}_i$。 | 于是 $\text{dp}_i=\sum_{1\le j\lt i}\text{LCP}(T_i,T_j)=\text{dp}_j+(i-j)\text{height}_i$。 | ||
- | 另外该题也可以用笛卡尔树维护。 | + | 另外该题也可以用笛卡尔树或并查集等维护。 |
+ | |||
+ | <hidden 查看代码> | ||
+ | <code cpp> | ||
+ | const int MAXN=5e5+5,MAXM=20; | ||
+ | namespace SA{ | ||
+ | int sa[MAXN],rk[MAXN],height[MAXN],x[MAXN],y[MAXN],c[MAXN]; | ||
+ | void get_sa(char *s,int n,int m){ | ||
+ | _rep(i,0,m)c[i]=0; | ||
+ | _rep(i,1,n)c[x[i]=s[i]]++; | ||
+ | _rep(i,1,m)c[i]+=c[i-1]; | ||
+ | for(int i=n;i;i--)sa[c[x[i]]--]=i; | ||
+ | for(int k=1;k<n;k<<=1){ | ||
+ | int pos=0; | ||
+ | _rep(i,n-k+1,n)y[++pos]=i; | ||
+ | _rep(i,1,n)if(sa[i]>k)y[++pos]=sa[i]-k; | ||
+ | _rep(i,0,m)c[i]=0; | ||
+ | _rep(i,1,n)c[x[i]]++; | ||
+ | _rep(i,1,m)c[i]+=c[i-1]; | ||
+ | for(int i=n;i;i--)sa[c[x[y[i]]]--]=y[i],y[i]=0; | ||
+ | swap(x,y); | ||
+ | pos=0,y[n+1]=0; | ||
+ | _rep(i,1,n)x[sa[i]]=(y[sa[i]]==y[sa[i-1]]&&y[sa[i]+k]==y[sa[i-1]+k])?pos:++pos; | ||
+ | if(pos==n)break; | ||
+ | m=pos; | ||
+ | } | ||
+ | _rep(i,1,n)rk[sa[i]]=i; | ||
+ | } | ||
+ | void get_height(char *s,int n){ | ||
+ | for(int i=1,k=0;i<=n;i++){ | ||
+ | if(k)k--; | ||
+ | while(s[i+k]==s[sa[rk[i]-1]+k])k++; | ||
+ | height[rk[i]]=k; | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | char buf[MAXN]; | ||
+ | pair<int,int> Stack[MAXN]; | ||
+ | LL dp[MAXN]; | ||
+ | int main() | ||
+ | { | ||
+ | scanf("%s",buf+1); | ||
+ | int n=strlen(buf+1); | ||
+ | SA::get_sa(buf,n,'z'); | ||
+ | SA::get_height(buf,n); | ||
+ | LL ans=1LL*(n-1)*n*(n+1)/2; | ||
+ | int top=0; | ||
+ | Stack[0]=make_pair(0,0); | ||
+ | _rep(i,1,n){ | ||
+ | while(top&&Stack[top].second>SA::height[i])top--; | ||
+ | dp[i]=dp[Stack[top].first]+1LL*(i-Stack[top].first)*SA::height[i],ans-=dp[i]*2; | ||
+ | Stack[++top]=make_pair(i,SA::height[i]); | ||
+ | } | ||
+ | enter(ans); | ||
+ | return 0; | ||
+ | } | ||
+ | </code> | ||
+ | </hidden> |