【bzoj4278】[ONTAK2015]Tasowanie 后缀数组

本文介绍了一种用于找到两个数字串进行二路归并后字典序最小的新串T的算法实现,通过比较后缀数组大小来确定最优归并方式,并附带详细代码。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Description

给定两个数字串A和B,通过将A和B进行二路归并得到一个新的数字串T,请找到字典序最小的T。
Input

第一行包含一个正整数n(1<=n<=200000),表示A串的长度。
第二行包含n个正整数,其中第i个数表示Ai
第三行包含一个正整数m(1<=m<=200000),表示B串的长度。
第四行包含m个正整数,其中第i个数表示Bi
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

题解
Orz YZH
在YZH大神的指导下,本蒟蒻终于AC了,YZH大神实在是太强了!!!!
比较两个数组的后缀数组大小,肯定是取rk小的。

代码

#include<bits/stdc++.h>
#define ll long long
#define inf 1000000000
#define mod 1000000007
using namespace std;
inline 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;
}
const int N=2333333;//Orz YZH
int n,m,tot,ans[N],rk[N],sa[N];
int sta[N],stb[N],tsa[N];
int a[N],b[N],A[N],B[N];
void SA(int n)
{
    for (int i=1;i<=n;i++) sta[rk[i]]++;
    for (int i=1;i<=1001;i++) sta[i]+=sta[i-1];
    for (int i=n;i;i--) sa[sta[rk[i]]--]=i;
    rk[sa[1]]=1;
    for (int i=2;i<=n;i++)rk[sa[i]]=rk[sa[i-1]]+(rk[sa[i-1]]!=rk[sa[i]]);
    for (int L=1;rk[sa[n]]!=n;L<<=1)
    {
        for (int i=0;i<=n;i++) sta[i]=stb[i]=0;
        for (int i=1;i<=n;i++) A[i]=rk[i],B[i]=rk[i+L];
        for (int i=1;i<=n;i++) sta[A[i]]++,stb[B[i]]++;
        for (int i=1;i<=n;i++) sta[i]+=sta[i-1],stb[i]+=stb[i-1];
        for (int i=n;i;i--) tsa[stb[B[i]]--]=i;
        for (int i=n;i;i--) sa[sta[A[tsa[i]]]--]=tsa[i];
        rk[sa[1]]=1;
        for (int i=2;i<=n;i++)rk[sa[i]]=rk[sa[i-1]]+(A[sa[i-1]]!=A[sa[i]]||B[sa[i-1]]!=B[sa[i]]);
    }
}
int main()
{
    n=read();
    for (int i=1;i<=n;i++) a[i]=rk[i]=read();rk[n+1]=1001;n++;
    m=read();
    for (int i=1;i<=m;i++) b[i+n]=rk[i+n]=read();b[n+m+1]=rk[n+m+1]=1001;m++;
    SA(n+m);
    int i=1,j=n+1;
    while (i<n&&j<n+m)
    {
        if (rk[i]<rk[j]) ans[++tot]=a[i++];else ans[++tot]=b[j++];
    }
    while (i<n) ans[++tot]=a[i++];
    while (j<n+m) ans[++tot]=b[j++];
    for (int i=1;i<=tot;i++) printf("%d ",ans[i]);
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值