【BZOJ-4278】Tasowanie 后缀数组 + 归并
4278: [ONTAK2015]Tasowanie
Time Limit: 10 Sec Memory Limit: 256 MBSubmit: 164 Solved: 80
[Submit][Status][Discuss]
Description
给定两个数字串A和B,通过将A和B进行二路归并得到一个新的数字串T,请找到字典序最小的T。
Input
第一行包含一个正整数n(1<=n<=200000),表示A串的长度。
第二行包含n个正整数,其中第i个数表示A[i](1<=A[i]<=1000)。
第三行包含一个正整数m(1<=m<=200000),表示B串的长度。
第四行包含m个正整数,其中第i个数表示B[i](1<=B[i]<=1000)。
Output
输出一行,包含n+m个正整数,即字典序最小的T串。
Sample Input
6
1 2 3 1 2 4
7
1 2 2 1 3 4 3
1 2 3 1 2 4
7
1 2 2 1 3 4 3
Sample Output
1 1 2 2 1 2 3 1 2 3 4 3
4
HINT
Source
Solution
一眼秒后缀数组裸题?算出rank数组来
二路归并的输出答案即可....
PS感觉Claris不会传裸题上来的,于是%了发他的做法,是个贪心
Code
#include<cstdio> #include<cstring> #include<algorithm> #include<cmath> using namespace std; int read() { int x=0,f=1; char ch=getchar(); while (ch<'0' || ch>'9') {if (ch=='-') f=-1; ch=getchar();} while (ch>='0' && ch<='9') {x=x*10+ch-'0'; ch=getchar();} return x*f; } #define maxn 400010 int len,val[maxn]; int S[maxn]; int SA[maxn]; int ws[maxn],wa[maxn],wv[maxn],wb[maxn]; int cmp(int *r,int a,int b,int l) { return r[a]==r[b]&&r[a+l]==r[b+l]; } void DA(int *r,int *sa,int n,int m) { int p,*x=wa,*y=wb,*t; for (int i=0; i<m; i++) ws[i]=0; for (int i=0; i<n; i++) ws[x[i]=r[i]]++; for (int i=1; i<m; i++) ws[i]+=ws[i-1]; for (int i=n-1; i>=0; i--) sa[--ws[x[i]]]=i; p=1; for (int j=1; p<n; j*=2,m=p) { p=0; for (int i=n-j; i<n; i++) y[p++]=i; for (int i=0; i<n; i++) if (sa[i]>=j) y[p++]=sa[i]-j; for (int i=0; i<n; i++) wv[i]=x[y[i]]; for (int i=0; i<m; i++) ws[i]=0; for (int i=0; i<n; i++) ws[wv[i]]++; for (int i=1; i<m; i++) ws[i]+=ws[i-1]; for (int i=n-1; i>=0; i--) sa[--ws[wv[i]]]=y[i]; t=x; x=y; y=t; p=1; x[sa[0]]=0; for (int i=1; i<n; i++) x[sa[i]]=cmp(y,sa[i-1],sa[i],j)?p-1:p++; } } int rank[maxn],height[maxn]; void calheight(int *r,int *sa,int n) { int k=0; for (int i=1; i<=n; i++) rank[sa[i]]=i; for (int i=0; i<n; height[rank[i++]]=k) {k?k--:0;for (int j=sa[rank[i]-1]; r[i+k]==r[j+k]; k++);} } int N,M; int main() { N=read(); for (int i=0; i<N; i++) S[i]=read(); S[N]=1001; M=read(); for (int i=1; i<=M; i++) S[i+N]=read(); S[N+M+1]=0; DA(S,SA,N+M+2,1002); calheight(S,SA,N+M+1); int a=0,b=N+1; for (int i=0; i<=N+M; i++) { if (i==N) continue; if (a==N) {for (int j=b; j<=N+M; j++) printf("%d ",S[j]); break;} if (b==N+M+1) {for (int j=a; j<N; j++) printf("%d ",S[j]); break;} if (rank[a]<rank[b]) printf("%d ",S[a]),a++; else printf("%d ",S[b]),b++; } return 0; }
跑得怎么比hs(hen)y快这么多..但还是被卡第一页了....
——It's a lonely path. Don't make it any lonelier than it has to be.