您的位置:首页 > 其它

bzoj 4278: [ONTAK2015]Tasowanie (后缀数组)

2016-05-12 16:49 363 查看

4278: [ONTAK2015]Tasowanie

Time Limit: 10 Sec Memory Limit: 256 MB

Submit: 161 Solved: 77

[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

Sample Output

1 1 2 2 1 2 3 1 2 3 4 3 4

HINT

Source

By Claris

[Submit][Status][Discuss]

题解:将两个串连在一起,然后求后缀数组就可以了。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define N 500003
using namespace std;
int n,m,len,p,q,k;
int sa[2]
,rank[2]
,v
,a
,b
;
void solve(int sa
,int rank
,int sa1
,int rank1
)
{
for (int i=1;i<=len;i++)  v[rank[sa[i]]]=i;
for (int i=len;i>=1;i--)
if (sa[i]-k>0)
sa1[v[rank[sa[i]-k]]--]=sa[i]-k;
for (int i=len-k+1;i<=len;i++)
sa1[v[rank[i]]--]=i;
for (int i=1;i<=len;i++)
rank1[sa1[i]]=rank1[sa1[i-1]]+(rank[sa1[i]]!=rank[sa1[i-1]]||rank[sa1[i]+k]!=rank[sa1[i-1]+k]);
}
void work()
{
p=0; q=1;
for (int i=1;i<=len;i++) v[a[i]]++;
for (int i=1;i<=1001;i++) v[i]+=v[i-1];
for (int i=1;i<=len;i++)
sa[p][v[a[i]]--]=i;
for (int i=1;i<=len;i++)
rank[p][sa[p][i]]=rank[p][sa[p][i-1]]+(a[sa[p][i]]!=a[sa[p][i-1]]);
k=1;
while (k<len){
solve(sa[p],rank[p],sa[q],rank[q]);
p^=1; q^=1; k<<=1;
}
}

int main()
{
scanf("%d",&n);
for (int i=1;i<=n;i++) scanf("%d",&a[i]);
a[n+1]=1001;
scanf("%d",&m);
for (int i=1;i<=m;i++)  scanf("%d",&a[n+1+i]);
len=n+m+1;
work();
int head=1; int head1=n+2;
int i=1;
while (i<=n+m&&head<=n&&head1<=n+m+1)
{
i++;
if (rank[p][head]<rank[p][head1]) printf("%d ",a[head]),head++;
else  printf("%d ",a[head1]),head1++;
}
for (int i=head;i<=n;i++)
printf("%d ",a[i]);
for (int i=head1;i<=n+m+1;i++)
printf("%d ",a[i]);
printf("\n");
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: