给定两个数字串A和B,通过将A和B进行二路归并得到一个新的数字串T,请找到字典序最小的T。
#include <cstdio> #include <cstring> #include <iostream> using namespace std; const int maxn=400010; int N,M,n,m,maxx; int r[maxn],ra[maxn],rb[maxn],sa[maxn],st[maxn],rank[maxn]; void work() { int i,j,p,*x=ra,*y=rb; for(i=0;i<n;i++) st[x[i]=r[i]]++; for(i=1;i<m;i++) st[i]+=st[i-1]; for(i=n-1;i>=0;i--) sa[--st[x[i]]]=i; for(j=p=1;p<n;j<<=1,m=p) { for(i=n-j,p=0;i<n;i++) y[p++]=i; for(i=0;i<n;i++) if(sa[i]>=j) y[p++]=sa[i]-j; for(i=0;i<m;i++) st[i]=0; for(i=0;i<n;i++) st[x[y[i]]]++; for(i=1;i<m;i++) st[i]+=st[i-1]; for(i=n-1;i>=0;i--) sa[--st[x[y[i]]]]=y[i]; for(swap(x,y),i=p=1,x[sa[0]]=0;i<n;i++) x[sa[i]]=(y[sa[i-1]]==y[sa[i]]&&y[sa[i-1]+j]==y[sa[i]+j])?p-1:p++; } for(i=0;i<n;i++) rank[sa[i]]=i; } int main() { int i; scanf("%d",&N); for(i=0;i<N;i++) scanf("%d",&r[i]),m=max(m,r[i]); scanf("%d",&M); for(i=0;i<M;i++) scanf("%d",&r[N+i+1]),m=max(m,r[N+i+1]); r[N]=m+1,n=N+M+2,m+=2; work(); int a=0,b=N+1; for(i=0;i<N+M;i++) { if(rank[a]>rank[b]&&b<N+M+1) printf("%d ",r[b++]); else printf("%d ",r[a++]); } printf("\n"); return 0; }
【BZOJ4278】[ONTAK2015]Tasowanie 后缀数组
原文:http://www.cnblogs.com/CQzhangyu/p/6272283.html