题:https://ac.nowcoder.com/acm/contest/5666/A
题意:给定字符串,依题意求出每个后缀串的B数组,然后进行字典序排序
分析:直接通过1~n串的B数组,我们无法根据当前的B数组来推出其他后缀的B数组,如果可以则直接后缀数组即可;
通过观察,我们可以设立一个R[i]数组表示B[i]后缀i...n第2个0出现的位置,那么R[i]截取出来的那一段一定是”0X0“(X代表若干个1);
为什么要这么取呢?因为对于”0X0“的字典序比较,此时的字典树就是改字符串的长度,而对于R[i]后面的部分,通过举例可以发现,R[i]后面部分与B[1]的某一后缀相同,所以对于"0X0”长度相同的部分他们的字典序就等于其在B[1]中的后缀字典序。(这部分对B[1]进行后缀数组的预处理即可)

#include<bits/stdc++.h> using namespace std; #define pb push_back #define MP make_pair typedef long long ll; typedef unsigned long long ull; const int mod=998244353; const int M=1e5+5; const int inf=0x3f3f3f3f; const ll INF=1e18; struct SA{ int sa[M],c[M],Rank[M],t1[M],t2[M]; int n; void gao(int* s,int m){ s[++n]=0; int* x=t1,*y=t2; for(int i=0;i<m;i++) c[i]=0; for(int i=0;i<n;i++) c[x[i]=s[i]]++; for(int i=1;i<m;i++) c[i]+=c[i - 1] ; for(int i=n-1; i >= 0; i--) sa[--c[x[i]]]=i; for(int k=1;k<=n;k<<=1){ int p=0 ; for(int i=n-k;i<n;i++) y[p++]=i ; for(int i=0;i<n;i++) if(sa[i]>=k) y[p++]=sa[i]-k; for(int i=0;i<m;i++) c[i]=0; for(int i=0;i<n;i++) c[x[y[i]]]++; for(int i=1;i<m;i++) c[i]+=c[i-1]; for(int i=n-1;i>= 0; i--) sa[--c[x[y[i]]]]=y[i]; swap(x,y);p =1;x[sa[0]]=0; for(int i=1;i<n;i++) x[sa[i]]=y[sa[i-1]]==y[sa[i]]&&y[sa[i-1]+k]==y[sa[i]+k]?p-1:p++; if(p>=n)break ; m=p; } n--; for(int i=0;i<=n;i++)Rank[sa[i]]=i; } }suf; char s[M]; int R[M],B[M],ans[M]; int n; int Find(int x){ return x>=n?-1:suf.Rank[x]; } int main(){ while(~scanf("%d%s",&n,s)){ suf.n=n; for(int i=0,j;i<n;i=j+1){ j=i; while(j+1<n&&s[j+1]==s[i]) j++; for(int k=i;k<=j;k++) R[k]=j+1; } for(int i=0;i<n;i++) cout<<R[i]<<' '; cout<<endl; ///构建B[1]数组 int las0=-1,las1=-1; for(int i=0;i<n;i++){ if(s[i]=='a'){ if(las0==-1)B[i]=0; else B[i]=i-las0; las0=i; } else{ if(las1==-1)B[i]=0; else B[i]=i-las1; las1=i; } } suf.gao(B,n+3); for(int i=0;i<n;i++) ans[i]=i; sort(ans,ans+n,[&](int X,int Y){ if(R[X]-X!=R[Y]-Y) return R[X]-X<R[Y]-Y; if(R[X]>=n||R[Y]>=n)///假设只有有一个R[X]满足>=n,那么它必然在B中全“0”,而另一个至少有一个非“0”,所以以>=n为优先级 return R[X]>=n;///而把他单独取出来的原因是它不能单纯地通过B[1]的后缀数组求出,理由也很简单:若只有有一个R[X]满足>=n,那么它实际的字典序会“破坏”B[1]的后缀数组 return Find(R[X]+1)<Find(R[Y]+1); }); for(int i=0;i<n;i++) printf("%d ",ans[i]+1); printf(" "); } return 0; }