这里会显示出您选择的修订版和当前版本之间的差别。
| 两侧同时换到之前的修订记录 前一修订版 后一修订版 | 前一修订版 | ||
|
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> | ||