后缀数组(SA)做题记录
本文属于抽象文学,读者大概是读不懂的(本来也是给自己写的
SA 真的是个好东西,好呀好东西。
基础定义
$sa$ 数组:后缀排序后排名为 $i$ 的后缀的起始位置下标。
$rk$ 数组:起始下标为 $i$ 的后缀的排名。
$height$ 数组:后缀排序后排名为 $i$ 和 $i-1$ 的最长公共前缀长度(Lcp)
模板:(小bug:在模板的第21行会出现越界的情况(访问到 $Y_{n+1},只有在 $X_i$ 出现 $0$ 的时候会出问题(加一即可规避))
标准写法是写个 cmp 函数专门判断。
1 char ch[N]; 2 struct Suffix_Array 3 { 4 ll m=200,X[N],Y[N],c[N],num[N],sa[N],height[N],rk[N],lg[N],st[N][23]; 5 void Sa() 6 { 7 for(int i=1;i<=n;i++)X[i]=ch[i],c[X[i]]++; 8 for(int i=2;i<=m;i++)c[i]+=c[i-1]; 9 for(int i=n;i>=1;i--)sa[c[X[i]]--]=i; 10 for(int k=1,p=0;k<=n;k=k<<1,p=0) 11 { 12 for(int i=n-k+1;i<=n;i++)Y[++p]=i; 13 for(int i=1;i<=n;i++)if(sa[i]>k)Y[++p]=sa[i]-k; 14 for(int i=1;i<=m;i++)c[i]=0; 15 for(int i=1;i<=n;i++)c[X[i]]++; 16 for(int i=2;i<=m;i++)c[i]+=c[i-1]; 17 for(int i=n;i>=1;i--)sa[c[X[Y[i]]]--]=Y[i],Y[i]=0; 18 swap(X,Y);p=1;X[sa[1]]=1; 19 for(int i=2;i<=n;i++) 20 { 21 if(Y[sa[i]]==Y[sa[i-1]]&&Y[sa[i]+k]==Y[sa[i-1]+k])X[sa[i]]=p; 22 else X[sa[i]]=++p; 23 } 24 if(p==n)return;m=p; 25 } 26 } 27 void Height() 28 { 29 ll k=0; 30 for(int i=1;i<=n;i++)rk[sa[i]]=i; 31 for(int i=1;i<=n;i++) 32 { 33 if(rk[i]==1)continue; 34 if(k)k--; 35 int j=sa[rk[i]-1]; 36 while(i+k<=n&&j+k<=n&&ch[i+k]==ch[j+k])k++; 37 height[rk[i]]=k; 38 } 39 } 40 void St() 41 { 42 for(int i=2;i<=n;i++)lg[i]=lg[i>>1]+1; 43 for(int i=1;i<=n;i++)st[i][0]=height[i]; 44 for(int j=1;j<=20;j++)for(int i=1;i+(1<<j)-1<=n;i++) 45 st[i][j]=min(st[i][j-1],st[i+(1<<j-1)][j-1]); 46 } 47 int Lcp(int l,int r) //原数组中 l,r的lcp长度 48 { 49 if((l=rk[l])>(r=rk[r]))swap(l,r); //若是直接在后缀数组sa[i]上求就删除 50 int d=lg[r-l++]; 51 return min(st[l][d],st[r-(1<<d)+1][d]); 52 } 53 }SA;
题目:
板子
1 #include<bits/stdc++.h> 2 using namespace std; 3 4 typedef long long ll; 5 const int N=1e6+3; 6 int n,m=200,X[N],Y[N],c[N],sa[N],height[N],rk[N]; 7 char ch[N]; 8 void Sa() 9 { 10 for(int i=1;i<=n;i++)X[i]=ch[i],c[X[i]]++; 11 for(int i=2;i<=m;i++)c[i]+=c[i-1]; 12 for(int i=n;i>=1;i--)sa[c[X[i]]--]=i; 13 for(int k=1,p=0;k<=n;k=k<<1,p=0) 14 { 15 for(int i=n-k+1;i<=n;i++)Y[++p]=i; 16 for(int i=1;i<=n;i++)if(sa[i]>k)Y[++p]=sa[i]-k; 17 for(int i=1;i<=m;i++)c[i]=0; 18 for(int i=1;i<=n;i++)c[X[i]]++; 19 for(int i=2;i<=m;i++)c[i]+=c[i-1]; 20 for(int i=n;i>=1;i--)sa[c[X[Y[i]]]--]=Y[i],Y[i]=0; 21 swap(X,Y);p=1;X[sa[1]]=1; 22 for(int i=2;i<=n;i++) 23 { 24 if(Y[sa[i]]==Y[sa[i-1]]&&Y[sa[i]+k]==Y[sa[i-1]+k])X[sa[i]]=p; 25 else X[sa[i]]=++p; 26 } 27 if(p==n)return;m=p; 28 } 29 } 30 void Height() 31 { 32 int k=0; 33 for(int i=1;i<=n;i++)rk[sa[i]]=i; 34 for(int i=1;i<=n;i++) 35 { 36 if(rk[i]==1)continue; 37 if(k)k--; 38 int j=sa[rk[i]-1]; 39 while(i+k<=n&&j+k<=n&&ch[i+k]==ch[j+k])k++; 40 height[rk[i]]=k; 41 } 42 } 43 int main() 44 { 45 cin>>(ch+1);n=strlen(ch+1); 46 Sa();Height(); 47 for(int i=1;i<=n;i++)cout<<sa[i]<<" "; 48 return 0; 49 }
利用 $height$ 数组的性质,总个数减去相邻两个的 Lcp 即可。
1 #include<bits/stdc++.h> 2 using namespace std; 3 4 typedef long long ll; 5 const int N=1e6+3; 6 ll n,m=200,X[N],Y[N],c[N],sa[N],height[N],rk[N]; 7 char ch[N]; 8 void Sa() 9 { 10 for(int i=1;i<=n;i++)X[i]=ch[i],c[X[i]]++; 11 for(int i=2;i<=m;i++)c[i]+=c[i-1]; 12 for(int i=n;i>=1;i--)sa[c[X[i]]--]=i; 13 for(int k=1,p=0;k<=n;k=k<<1,p=0) 14 { 15 for(int i=n-k+1;i<=n;i++)Y[++p]=i; 16 for(int i=1;i<=n;i++)if(sa[i]>k)Y[++p]=sa[i]-k; 17 for(int i=1;i<=m;i++)c[i]=0; 18 for(int i=1;i<=n;i++)c[X[i]]++; 19 for(int i=2;i<=m;i++)c[i]+=c[i-1]; 20 for(int i=n;i>=1;i--)sa[c[X[Y[i]]]--]=Y[i],Y[i]=0; 21 swap(X,Y);p=1;X[sa[1]]=1; 22 for(int i=2;i<=n;i++) 23 { 24 if(Y[sa[i]]==Y[sa[i-1]]&&Y[sa[i]+k]==Y[sa[i-1]+k])X[sa[i]]=p; 25 else X[sa[i]]=++p; 26 } 27 if(p==n)return;m=p; 28 } 29 } 30 void Height() 31 { 32 int k=0; 33 for(int i=1;i<=n;i++)rk[sa[i]]=i; 34 for(int i=1;i<=n;i++) 35 { 36 if(rk[i]==1)continue; 37 if(k)k--; 38 int j=sa[rk[i]-1]; 39 while(i+k<=n&&j+k<=n&&ch[i+k]==ch[j+k])k++; 40 height[rk[i]]=k; 41 } 42 } 43 int main() 44 { 45 cin>>n>>(ch+1); 46 Sa();Height();ll s=n*(n-1)/2+n; 47 for(int i=1;i<=n;i++)s-=height[i]; 48 cout<<s<<endl; 49 return 0; 50 }
将所有串串用分隔符串在一起(一定要不同且最后一定不能有多的),分别染色。
然后就双指针暴力扫使得每种颜色都出现过然后求 Lcp 即可。
1 #include<bits/stdc++.h> 2 using namespace std; 3 4 typedef long long ll; 5 const int N=1e6+13; 6 int n,B,ok,col[N],cnt[N],lg[N],st[N][23]; 7 int m=2000,X[N],Y[N],c[N],sa[N],height[N],rk[N]; 8 char ch[N],ca[N]; 9 void Sa() 10 { 11 for(int i=1;i<=n;i++)X[i]=ch[i],c[X[i]]++; 12 for(int i=2;i<=m;i++)c[i]+=c[i-1]; 13 for(int i=n;i>=1;i--)sa[c[X[i]]--]=i; 14 for(int k=1,p=0;k<=n;k=k<<1,p=0) 15 { 16 for(int i=n-k+1;i<=n;i++)Y[++p]=i; 17 for(int i=1;i<=n;i++)if(sa[i]>k)Y[++p]=sa[i]-k; 18 for(int i=1;i<=m;i++)c[i]=0; 19 for(int i=1;i<=n;i++)c[X[i]]++; 20 for(int i=2;i<=m;i++)c[i]+=c[i-1]; 21 for(int i=n;i>=1;i--)sa[c[X[Y[i]]]--]=Y[i],Y[i]=0; 22 swap(X,Y);p=1;X[sa[1]]=1; 23 for(int i=2;i<=n;i++) 24 { 25 if(Y[sa[i]]==Y[sa[i-1]]&&Y[sa[i]+k]==Y[sa[i-1]+k])X[sa[i]]=p; 26 else X[sa[i]]=++p; 27 } 28 if(n==p)return;m=p; 29 } 30 } 31 void Height() 32 { 33 int k=0; 34 for(int i=1;i<=n;i++)rk[sa[i]]=i; 35 for(int i=1;i<=n;i++) 36 { 37 if(rk[i]==1)continue; 38 if(k)k--; 39 int j=sa[rk[i]-1]; 40 while(i+k<=n&&j+k<=n&&ch[i+k]==ch[j+k])k++; 41 height[rk[i]]=k; 42 } 43 } 44 void Add(int x) 45 { 46 int y=col[x]; 47 if(!y)return; 48 if(!cnt[y])ok++; 49 cnt[y]++; 50 } 51 void Del(int x) 52 { 53 int y=col[x]; 54 if(!y)return; 55 cnt[y]--; 56 if(!cnt[y])ok--; 57 } 58 void St() 59 { 60 for(int i=2;i<=n;i++)lg[i]=lg[i>>1]+1; 61 for(int i=1;i<=n;i++)st[i][0]=height[i]; 62 for(int j=1;j<=20;j++)for(int i=1;i+(1<<j)-1<=n;i++) 63 st[i][j]=min(st[i][j-1],st[i+(1<<j-1)][j-1]); 64 } 65 int Ask(int l,int r) 66 { 67 int d=lg[r-l+1]; 68 return min(st[l][d],st[r-(1<<d)+1][d]); 69 } 70 int main() 71 { 72 cin>>B; 73 for(int t=1;t<=B;t++) 74 { 75 cin>>(ca+1);int z=strlen(ca+1); 76 for(int i=1;i<=z;i++)ch[++n]=ca[i],col[n]=t; 77 ch[++n]='{'; 78 } 79 n--;Sa();Height();St();int i=0; 80 while(ok<B&&i<n)i++,Add(sa[i]); 81 if(ok<B){cout<<0;return 0;} 82 int ans=Ask(2,i); 83 for(int j=1;i<=n&&j<=n;) 84 { 85 Del(sa[j]),j++; 86 while(ok<B&&i<n)i++,Add(sa[i]); 87 if(ok<B){cout<<ans;return 0;} 88 ans=max(ans,Ask(j+1,i)); 89 } 90 cout<<ans; 91 }
分别考虑每个 $height_i$ 的贡献,相当于就是求全局的所有子区间的 $min$ 之和。
这就是经典题,具体的可以看 这里
1 #include<bits/stdc++.h> 2 using namespace std; 3 4 typedef long long ll; 5 const int N=1e6+3; 6 ll n,m=200,X[N],Y[N],c[N],sa[N],height[N],rk[N],sta[N],ans[N]; 7 char ch[N]; 8 void Sa() 9 { 10 for(int i=1;i<=n;i++)X[i]=ch[i],c[X[i]]++; 11 for(int i=2;i<=m;i++)c[i]+=c[i-1]; 12 for(int i=n;i>=1;i--)sa[c[X[i]]--]=i; 13 for(int k=1,p=0;k<=n;k=k<<1,p=0) 14 { 15 for(int i=n-k+1;i<=n;i++)Y[++p]=i; 16 for(int i=1;i<=n;i++)if(sa[i]>k)Y[++p]=sa[i]-k; 17 for(int i=1;i<=m;i++)c[i]=0; 18 for(int i=1;i<=n;i++)c[X[i]]++; 19 for(int i=2;i<=m;i++)c[i]+=c[i-1]; 20 for(int i=n;i>=1;i--)sa[c[X[Y[i]]]--]=Y[i],Y[i]=0; 21 swap(X,Y);p=1;X[sa[1]]=1; 22 for(int i=2;i<=n;i++) 23 { 24 if(Y[sa[i]]==Y[sa[i-1]]&&Y[sa[i]+k]==Y[sa[i-1]+k])X[sa[i]]=p; 25 else X[sa[i]]=++p; 26 } 27 if(p==n)return;m=p; 28 } 29 } 30 void Height() 31 { 32 int k=0; 33 for(int i=1;i<=n;i++)rk[sa[i]]=i; 34 for(int i=1;i<=n;i++) 35 { 36 if(rk[i]==1)continue; 37 if(k)k--; 38 int j=sa[rk[i]-1]; 39 while(i+k<=n&&j+k<=n&&ch[i+k]==ch[j+k])k++; 40 height[rk[i]]=k; 41 } 42 } 43 ll Work() 44 { 45 ll top=0,s=0; 46 for(int i=1;i<=n;i++) 47 { 48 while(top&&height[sta[top]]>=height[i])top--; 49 ans[i]=ans[sta[top]]+height[i]*(i-sta[top]); 50 s+=ans[i];sta[++top]=i; 51 } 52 return 2*s; 53 } 54 int main() 55 { 56 cin>>(ch+1);n=strlen(ch+1); 57 Sa();Height();ll s=n*(n-1)*(n+1)/2; 58 cout<<s-Work(); 59 }
和 4. 本质相同。
1 #include<bits/stdc++.h> 2 using namespace std; 3 4 typedef long long ll; 5 const int N=1e6+3; 6 ll n,na,nb,m,c[N],X[N],Y[N],sa[N],height[N],rk[N],sta[N],ans[N]; 7 char ch[N],ca[N],cb[N]; 8 void Sa() 9 { 10 for(int i=1;i<=n;i++)X[i]=ch[i],c[X[i]]++; 11 for(int i=2;i<=m;i++)c[i]+=c[i-1]; 12 for(int i=n;i>=1;i--)sa[c[X[i]]--]=i; 13 for(int k=1,p=0;k<=n;k=k<<1,p=0) 14 { 15 for(int i=n-k+1;i<=n;i++)Y[++p]=i; 16 for(int i=1;i<=n;i++)if(sa[i]>k)Y[++p]=sa[i]-k; 17 for(int i=1;i<=m;i++)c[i]=0; 18 for(int i=1;i<=n;i++)c[X[i]]++; 19 for(int i=2;i<=m;i++)c[i]+=c[i-1]; 20 for(int i=n;i>=1;i--)sa[c[X[Y[i]]]--]=Y[i],Y[i]=0; 21 swap(X,Y);p=1;X[sa[1]]=1; 22 for(int i=2;i<=n;i++) 23 { 24 if(Y[sa[i]]==Y[sa[i-1]]&&Y[sa[i]+k]==Y[sa[i-1]+k])X[sa[i]]=p; 25 else X[sa[i]]=++p; 26 } 27 if(p==n)return;m=p; 28 } 29 } 30 void Height() 31 { 32 int k=0; 33 for(int i=1;i<=n;i++)rk[sa[i]]=i; 34 for(int i=1;i<=n;i++) 35 { 36 if(rk[i]==1)continue; 37 if(k)k--; 38 int j=sa[rk[i]-1]; 39 while(i+k<=n&&j+k<=n&&ch[i+k]==ch[j+k])k++; 40 height[rk[i]]=k; 41 } 42 } 43 ll Work() 44 { 45 ll top=0,s=0; 46 for(int i=1;i<=n;i++) 47 { 48 while(top&&height[sta[top]]>=height[i])top--; 49 ans[i]=ans[sta[top]]+height[i]*(i-sta[top]); 50 s+=ans[i];sta[++top]=i; 51 } 52 return s; 53 } 54 ll Solve() 55 { 56 m=200; 57 for(int i=1;i<N;i++)sa[i]=height[i]=rk[i]=X[i]=Y[i]=c[i]=0; 58 Sa();Height(); 59 return Work(); 60 } 61 int main() 62 { 63 cin>>(ca+1)>>(cb+1);na=strlen(ca+1);nb=strlen(cb+1); 64 ll sa=0,sb=0,s=0; 65 for(int i=1;i<=na;i++)ch[i]=ca[i]; 66 n=na;sa=Solve(); 67 for(int i=1;i<=nb;i++)ch[i]=cb[i]; 68 n=nb;sb=Solve();ch[++n]='#'; 69 for(int i=1;i<=na;i++)ch[++n]=ca[i]; 70 s=Solve(); 71 cout<<s-sa-sb<<endl; 72 }
差分一下,然后就变成所有串的 Lcp 和 3. 本质相同
1 #include<bits/stdc++.h> 2 using namespace std; 3 4 typedef long long ll; 5 const int N=2e6+3; 6 int n,B,ok,col[N],cnt[N],lg[N],st[N][23]; 7 int m=4000,X[N],Y[N],c[N],sa[N],height[N],rk[N],ch[N]; 8 void Sa() 9 { 10 for(int i=1;i<=n;i++)X[i]=ch[i],c[X[i]]++; 11 for(int i=2;i<=m;i++)c[i]+=c[i-1]; 12 for(int i=n;i>=1;i--)sa[c[X[i]]--]=i; 13 for(int k=1,p=0;k<=n;k=k<<1,p=0) 14 { 15 for(int i=n-k+1;i<=n;i++)Y[++p]=i; 16 for(int i=1;i<=n;i++)if(sa[i]>k)Y[++p]=sa[i]-k; 17 for(int i=1;i<=m;i++)c[i]=0; 18 for(int i=1;i<=n;i++)c[X[i]]++; 19 for(int i=2;i<=m;i++)c[i]+=c[i-1]; 20 for(int i=n;i>=1;i--)sa[c[X[Y[i]]]--]=Y[i],Y[i]=0; 21 swap(X,Y);p=1;X[sa[1]]=1; 22 for(int i=2;i<=n;i++) 23 { 24 if(Y[sa[i]]==Y[sa[i-1]]&&Y[sa[i]+k]==Y[sa[i-1]+k])X[sa[i]]=p; 25 else X[sa[i]]=++p; 26 } 27 if(n==p)return;m=p; 28 } 29 } 30 void Height() 31 { 32 int k=0; 33 for(int i=1;i<=n;i++)rk[sa[i]]=i; 34 for(int i=1;i<=n;i++) 35 { 36 if(rk[i]==1)continue; 37 if(k)k--; 38 int j=sa[rk[i]-1]; 39 while(i+k<=n&&j+k<=n&&ch[i+k]==ch[j+k])k++; 40 height[rk[i]]=k; 41 } 42 } 43 void Add(int x) 44 { 45 int y=col[x]; 46 if(!y)return; 47 if(!cnt[y])ok++; 48 cnt[y]++; 49 } 50 void Del(int x) 51 { 52 int y=col[x]; 53 if(!y)return; 54 cnt[y]--; 55 if(!cnt[y])ok--; 56 } 57 void St() 58 { 59 for(int i=2;i<=n;i++)lg[i]=lg[i>>1]+1; 60 for(int i=1;i<=n;i++)st[i][0]=height[i]; 61 for(int j=1;j<=20;j++)for(int i=1;i+(1<<j)-1<=n;i++) 62 st[i][j]=min(st[i][j-1],st[i+(1<<j-1)][j-1]); 63 } 64 int Ask(int l,int r) 65 { 66 int d=lg[r-l+1]; 67 return min(st[l][d],st[r-(1<<d)+1][d]); 68 } 69 int main() 70 { 71 cin>>B; 72 for(int t=1,z,x;t<=B;t++) 73 { 74 cin>>z>>x; 75 for(int i=1,y;i<z;i++)cin>>y,ch[++n]=y-x+2000,col[n]=t,x=y; 76 ch[++n]=++m; 77 } 78 n--;Sa();Height();St(); 79 int i=0; 80 while(ok<B&&i<n)i++,Add(sa[i]); 81 if(ok<B){cout<<1;return 0;} 82 int ans=Ask(2,i); 83 for(int j=1;i<=n&&j<=n;) 84 { 85 Del(sa[j]),j++; 86 while(ok<B&&i<n)i++,Add(sa[i]); 87 if(ok<B){cout<<ans+1;return 0;} 88 ans=max(ans,Ask(j+1,i)); 89 } 90 cout<<ans+1; 91 }
倍长一边串串,然后 SA 即可。
1 #include<bits/stdc++.h> 2 using namespace std; 3 4 typedef long long ll; 5 const int N=1e6+3; 6 int n,m=200,X[N],Y[N],c[N],sa[N],height[N],rk[N]; 7 char ch[N]; 8 void Sa() 9 { 10 for(int i=1;i<=n;i++)X[i]=ch[i],c[X[i]]++; 11 for(int i=2;i<=m;i++)c[i]+=c[i-1]; 12 for(int i=n;i>=1;i--)sa[c[X[i]]--]=i; 13 for(int k=1,p=0;k<=n;k=k<<1,p=0) 14 { 15 for(int i=n-k+1;i<=n;i++)Y[++p]=i; 16 for(int i=1;i<=n;i++)if(sa[i]>k)Y[++p]=sa[i]-k; 17 for(int i=1;i<=m;i++)c[i]=0; 18 for(int i=1;i<=n;i++)c[X[i]]++; 19 for(int i=2;i<=m;i++)c[i]+=c[i-1]; 20 for(int i=n;i>=1;i--)sa[c[X[Y[i]]]--]=Y[i],Y[i]=0; 21 swap(X,Y);p=1;X[sa[1]]=1; 22 for(int i=2;i<=n;i++) 23 { 24 if(Y[sa[i]]==Y[sa[i-1]]&&Y[sa[i]+k]==Y[sa[i-1]+k])X[sa[i]]=p; 25 else X[sa[i]]=++p; 26 } 27 if(n==p)return;m=p; 28 } 29 } 30 int main() 31 { 32 cin>>(ch+1);n=strlen(ch+1); 33 for(int i=1;i<=n;i++)ch[i+n]=ch[i]; 34 n*=2;Sa(); 35 for(int i=1;i<=n;i++)if(sa[i]<=n/2)cout<<ch[sa[i]+n/2-1]; 36 }
开始上强度。发现每次向后插入字符时,一切都变得神秘。
正难则反,反转字符串,每次插入一个前缀只会影响自己。提前跑出 height,发现每次的贡献就是加上自己和前驱,自己和后继,减去前驱和后继的贡献,维护一个 set 即可。
1 #include<bits/stdc++.h> 2 using namespace std; 3 4 typedef long long ll; 5 const int N=1e6+3; 6 ll n,m,a[N],X[N],Y[N],c[N],sa[N],height[N],rk[N],lg[N],st[N][23]; 7 map<ll,ll>mp;set<ll>q; 8 void Sa() 9 { 10 for(int i=1;i<=n;i++)X[i]=a[i],c[X[i]]++; 11 for(int i=2;i<=m;i++)c[i]+=c[i-1]; 12 for(int i=n;i>=1;i--)sa[c[X[i]]--]=i; 13 for(int k=1,p=0;k<=n;k=k<<1,p=0) 14 { 15 for(int i=n-k+1;i<=n;i++)Y[++p]=i; 16 for(int i=1;i<=n;i++)if(sa[i]>k)Y[++p]=sa[i]-k; 17 for(int i=1;i<=m;i++)c[i]=0; 18 for(int i=1;i<=n;i++)c[X[i]]++; 19 for(int i=2;i<=m;i++)c[i]+=c[i-1]; 20 for(int i=n;i>=1;i--)sa[c[X[Y[i]]]--]=Y[i],Y[i]=0; 21 swap(X,Y);p=1;X[sa[1]]=1; 22 for(int i=2;i<=n;i++) 23 { 24 if(Y[sa[i]]==Y[sa[i-1]]&&Y[sa[i]+k]==Y[sa[i-1]+k])X[sa[i]]=p; 25 else X[sa[i]]=++p; 26 } 27 if(p==n)return;m=p; 28 } 29 } 30 void Height() 31 { 32 ll k=0; 33 for(int i=1;i<=n;i++)rk[sa[i]]=i; 34 for(int i=1;i<=n;i++) 35 { 36 if(rk[i]==1)continue; 37 if(k)k--; 38 int j=sa[rk[i]-1]; 39 while(i+k<=n&&j+k<=n&&a[i+k]==a[j+k])k++; 40 height[rk[i]]=k; 41 } 42 } 43 void St() 44 { 45 for(int i=2;i<=n;i++)lg[i]=lg[i>>1]+1; 46 for(int i=1;i<=n;i++)st[i][0]=height[i]; 47 for(int j=1;j<=20;j++)for(int i=1;i+(1<<j)-1<=n;i++) 48 st[i][j]=min(st[i][j-1],st[i+(1<<j-1)][j-1]); 49 } 50 ll Ask(int l,int r) 51 { 52 int d=lg[r-l+1]; 53 return min(st[l][d],st[r-(1<<d)+1][d]); 54 } 55 int main() 56 { 57 cin>>n;ll ans=0; 58 for(int i=1;i<=n;i++)cin>>a[i],mp[a[i]]=0; 59 for(auto &p:mp)p.second=++m; 60 for(int i=1;i<=n;i++)a[i]=mp[a[i]]; 61 reverse(a+1,a+n+1);Sa();Height();St(); 62 for(int i=n;i>=1;i--) 63 { 64 int za=0,zb=0,zc=rk[i]; 65 q.insert(zc);auto it=q.find(zc); 66 if(it!=q.begin())za=*(--it),it++; 67 if(++it!=q.end())zb=*it; 68 if(za)ans-=Ask(za+1,zc); 69 if(zb)ans-=Ask(zc+1,zb); 70 if(za&&zb)ans+=Ask(za+1,zb); 71 ans+=n-i+1;cout<<ans<<endl; 72 } 73 }
搞出height,从大到小暴力并查集合并一下,维护最大值以及方案数即可。
1 #include<bits/stdc++.h> 2 using namespace std; 3 4 typedef long long ll; 5 const int N=1e6+5; 6 ll n,m=200,a[N],X[N],Y[N],c[N],sa[N],height[N],rk[N],f[N],sz[N],mx[N],mn[N],ans1[N],ans2[N],sx,sy=(ll)-1e18; 7 char ch[N]; 8 vector<int>e[N]; 9 void Sa() 10 { 11 for(int i=1;i<=n;i++)X[i]=ch[i],c[X[i]]++; 12 for(int i=2;i<=m;i++)c[i]+=c[i-1]; 13 for(int i=n;i>=1;i--)sa[c[X[i]]--]=i; 14 for(int k=1,p=0;k<=n;k=k<<1,p=0) 15 { 16 for(int i=n-k+1;i<=n;i++)Y[++p]=i; 17 for(int i=1;i<=n;i++)if(sa[i]>k)Y[++p]=sa[i]-k; 18 for(int i=1;i<=m;i++)c[i]=0; 19 for(int i=1;i<=n;i++)c[X[i]]++; 20 for(int i=2;i<=m;i++)c[i]+=c[i-1]; 21 for(int i=n;i>=1;i--)sa[c[X[Y[i]]]--]=Y[i],Y[i]=0; 22 swap(X,Y);p=1;X[sa[1]]=1; 23 for(int i=2;i<=n;i++) 24 { 25 if(Y[sa[i]]==Y[sa[i-1]]&&Y[sa[i]+k]==Y[sa[i-1]+k])X[sa[i]]=p; 26 else X[sa[i]]=++p; 27 } 28 if(p==n)return;m=p; 29 } 30 } 31 int Height() 32 { 33 int k=0; 34 for(int i=1;i<=n;i++)rk[sa[i]]=i; 35 for(int i=1;i<=n;i++) 36 { 37 if(rk[i]==1)continue; 38 if(k)k--; 39 int j=sa[rk[i]-1]; 40 while(j+k<=n&&i+k<=n&&ch[i+k]==ch[j+k])k++; 41 height[rk[i]]=k; 42 } 43 } 44 int F(int x){return f[x]==x?x:f[x]=F(f[x]);} 45 void Merge(int x,int y) 46 { 47 x=F(x);y=F(y);sx+=sz[x]*sz[y];sy=max(sy,max(mx[x]*mx[y],mn[x]*mn[y])); 48 f[y]=x;sz[x]+=sz[y];mx[x]=max(mx[x],mx[y]);mn[x]=min(mn[x],mn[y]); 49 } 50 int main() 51 { 52 cin>>n; 53 for(int i=1;i<=n;i++)cin>>ch[i]; 54 for(int i=1;i<=n;i++)cin>>a[i]; 55 Sa();Height(); 56 for(int i=1;i<=n;i++)f[i]=i,sz[i]=1,mx[i]=mn[i]=a[sa[i]]; 57 for(int i=2;i<=n;i++)e[height[i]].push_back(i); 58 for(int i=n-1;i>=0;i--) 59 { 60 for(int j:e[i])Merge(j,j-1); 61 if(sx)ans1[i]=sx,ans2[i]=sy; 62 } 63 for(int i=0;i<n;i++)cout<<ans1[i]<<" "<<ans2[i]<<endl; 64 return 0; 65 }
10.P4081 [USACO17DEC] Standing Out from the Herd P
对于每个后缀,要减去 $max$ 和来自上一个来自同一个串的lcp,来自不同串串的lcp。
1 #include<bits/stdc++.h> 2 using namespace std; 3 4 typedef long long ll; 5 const int N=1e6+3; 6 ll n,m=200,B,a[N],X[N],Y[N],c[N],sa[N],height[N],rk[N],lg[N],st[N][23],col[N],sx[N],ans[N]; 7 char ca[N]; 8 void Sa() 9 { 10 for(int i=1;i<=n;i++)X[i]=a[i],c[X[i]]++; 11 for(int i=2;i<=m;i++)c[i]+=c[i-1]; 12 for(int i=n;i>=1;i--)sa[c[X[i]]--]=i; 13 for(int k=1,p=0;k<=n;k=k<<1,p=0) 14 { 15 for(int i=n-k+1;i<=n;i++)Y[++p]=i; 16 for(int i=1;i<=n;i++)if(sa[i]>k)Y[++p]=sa[i]-k; 17 for(int i=1;i<=m;i++)c[i]=0; 18 for(int i=1;i<=n;i++)c[X[i]]++; 19 for(int i=2;i<=m;i++)c[i]+=c[i-1]; 20 for(int i=n;i>=1;i--)sa[c[X[Y[i]]]--]=Y[i],Y[i]=0; 21 swap(X,Y);p=1;X[sa[1]]=1; 22 for(int i=2;i<=n;i++) 23 { 24 if(Y[sa[i]]==Y[sa[i-1]]&&Y[sa[i]+k]==Y[sa[i-1]+k])X[sa[i]]=p; 25 else X[sa[i]]=++p; 26 } 27 if(n==p)return;m=p; 28 } 29 } 30 void Height() 31 { 32 ll k=0; 33 for(int i=1;i<=n;i++)rk[sa[i]]=i; 34 for(int i=1;i<=n;i++) 35 { 36 if(rk[i]==1)continue; 37 if(k)k--; 38 int j=sa[rk[i]-1]; 39 while(i+k<=n&&j+k<=n&&a[i+k]==a[j+k])k++; 40 height[rk[i]]=k; 41 } 42 } 43 void St() 44 { 45 for(int i=2;i<=n;i++)lg[i]=lg[i>>1]+1; 46 for(int i=1;i<=n;i++)st[i][0]=height[i]; 47 for(int j=1;j<=20;j++)for(int i=1;i+(1<<j)-1<=n;i++) 48 st[i][j]=min(st[i][j-1],st[i+(1<<j-1)][j-1]); 49 } 50 int Lcp(int l,int r) 51 { 52 int d=lg[r-l+1]; 53 return min(st[l][d],st[r-(1<<d)+1][d]); 54 } 55 int main() 56 { 57 cin>>B; 58 for(int t=1;t<=B;t++) 59 { 60 cin>>(ca+1);ll z=strlen(ca+1);ans[t]=z*(z+1)/2; 61 for(int i=1;i<=z;i++)a[++n]=ca[i],col[n]=t; 62 if(t<B)a[++n]=++m; 63 } 64 Sa();Height();St();ll la=0,lb=0; 65 for(int i=n;i>=1;i--) 66 { 67 if(!col[sa[i]])continue; 68 if(!la){la=i;continue;} 69 if(col[sa[i]]==col[sa[la]]&&!lb)continue; 70 if(col[sa[i]]!=col[sa[la]])sx[i]=Lcp(i+1,la),lb=la,la=i; 71 else sx[i]=Lcp(i+1,lb),la=i; 72 } 73 for(int i=1;i<=n;i++)ans[col[sa[i]]]-=max(sx[i],height[i]); 74 for(int i=1;i<=B;i++)cout<<ans[i]<<endl; 75 }

浙公网安备 33010602011771号