2020牛客暑期多校訓練營(第一場) B-Suffix Array 字尾陣列
阿新 • • 發佈:2020-07-16
題意
給你一個長度為\(n\)的字串\(S\),定義\(B\)陣列為:
- 如果存在一個位置\(j<i\)滿足\(S_j=S_i\),\(B_i=min_{1\le j<i,S_j=S_i}\{i-j\}\)。
- 否則,\(B_i=0\)。
對字串\(S\)的\(n\)個字尾的\(B\)陣列按字典序排序,輸出排序結果。
分析
定義字串\(S\)的\(n\)個字尾分別為\(s_1,s_2,\dots,s_n\),分別對應的\(B\)陣列為\(b_1,b_2,\dots,b_n\),能發現\(b_2,b_3,\dots,b_n\)和\(b_1\)除了自己本身的所有後綴只是第一個‘a'的位置和第一個’b'的位置變成了\(0\)
對於只有‘a'或只有’b'的字尾,它的\(B\)陣列一定是\(0\)後面有若干個\(1\),特判一下就好了。
Code
#include<algorithm> #include<iostream> #include<cstring> #include<iomanip> #include<sstream> #include<cstdio> #include<string> #include<vector> #include<bitset> #include<queue> #include<cmath> #include<stack> #include<set> #include<map> #define rep(i,x,n) for(int i=x;i<=n;++i) #define per(i,n,x) for(int i=n;i>=x;i--) #define sz(a) int(a.size()) #define rson mid+1,r,p<<1|1 #define pii pair<int,int> #define lson l,mid,p<<1 #define ll long long #define pb push_back #define mp make_pair #define se second #define fi first using namespace std; const double eps=1e-8; const int mod=1e9+7; const int N=1e5+10; const int inf=1e9; int n,b[N],sa[N],rk[N],wb[N],c[N],f[N][2],pre[2],d[N]; char s[N]; void bd(int m){ int *x=rk,*y=wb; rep(i,1,m) c[i]=0; rep(i,1,n) ++c[x[i]=b[i]]; rep(i,2,m) c[i]+=c[i-1]; per(i,n,1) sa[c[x[i]]--]=i; for(int k=1;k<=n;k<<=1){ int p=0; rep(i,n-k+1,n) y[++p]=i; rep(i,1,n) if(sa[i]>k) y[++p]=sa[i]-k; rep(i,1,m) c[i]=0; rep(i,1,n) ++c[ x[y[i]] ]; rep(i,2,m) c[i]+=c[i-1]; per(i,n,1) sa[ c[x[y[i]]]-- ]=y[i],y[i]=0; swap(x,y); x[sa[1]]=1; p=1; rep(i,2,n) x[sa[i]]= (y[sa[i]]==y[sa[i-1]]&&y[sa[i]+k]==y[sa[i-1]+k]) ? p : ++p; if(p>=n) break; m=p; } } bool cmp(int x,int y){ int l1=1,l2=1; if(f[x][0]&&f[x][1]) l1=max(f[x][0],f[x][1])-min(f[x][0],f[x][1])+1; if(f[y][0]&&f[y][1]) l2=max(f[y][0],f[y][1])-min(f[y][0],f[y][1])+1; if(l1==l2){ if(x+l1>n) return true; if(y+l2>n) return false; return rk[x+l1]<rk[y+l2]; } if(l1==1){ if(n-x+1<=l2-1) return true; return false; } if(l2==1){ if(n-y+1<=l1-1) return false; return true; } return l1<l2; } int main(){ //ios::sync_with_stdio(false); //freopen("in","r",stdin); while(~scanf("%d",&n)){ f[n+1][0]=f[n+1][1]=pre[0]=pre[1]=0; scanf("%s",s+1); int mx=0; rep(i,1,n){ if(pre[s[i]-'a']) b[i]=i-pre[s[i]-'a']+1; else b[i]=1; pre[s[i]-'a']=i; d[i]=i; mx=max(mx,b[i]); } per(i,n,1){ rep(j,0,1) f[i][j]=f[i+1][j]; f[i][s[i]-'a']=i; } bd(mx); rep(i,1,n) rk[sa[i]]=i; sort(d+1,d+n+1,cmp); rep(i,1,n){ printf("%d%c",d[i],i==n?'\n':' '); } } return 0; }