[BZOJ4278] [ONTAK2015]Tasowanie

传送门

http://www.lydsy.com/JudgeOnline/problem.php?id=4278

题目大意

给定两个数字串A和B,要求归并得到一个字典序最小的数字串T

题解

每次选取后缀最小的输出
用二分+HASH求出lcp后判断后缀大小

const
    maxn=200005;
    seed=131;
    mmod=1073741823;
var
    x:array[1..2,0..maxn]of int64;
    y,z:array[0..maxn]of longint;
    pow:array[0..maxn]of int64;
    i,j,k:longint;
    n,m,tt:longint;
function min(a,b:longint):longint;
begin
    if a>b then exit(b) else exit(a);
end;

function max(a,b:longint):longint;
begin
    if a>b then exit(a) else exit(b);
end;

function hash(kin,l,r:longint):int64;
begin
    exit((x[kin,r]-x[kin,l-1]*pow[r-l+1] mod mmod+mmod)mod mmod);
end;

function query(a,b:longint):longint;
var l,r,mid,tt:longint;
begin
    l:=1; r:=min(n-a+1,m-b+1); tt:=0;
    while l<=r do
        begin
            mid:=(l+r)>>1;
            if hash(1,a,a+mid-1)=hash(2,b,b+mid-1)
            then begin tt:=mid; l:=mid+1; end
            else r:=mid-1;
        end;
    exit(tt);
end;

begin
    readln(n); x[1,0]:=0;
    for i:=1 to n+1 do
        begin
            if i=n+1
            then x[1,i]:=2000
            else read(x[1,i]);
            y[i]:=x[1,i];
            x[1,i]:=(x[1,i-1]*seed+x[1,i])mod mmod;
        end;
    readln(m); x[2,0]:=0;
    for i:=1 to m+1 do
        begin
            if i=m+1
            then x[2,i]:=2000
            else read(x[2,i]);
            z[i]:=x[2,i];
            x[2,i]:=(x[2,i-1]*seed+x[2,i])mod mmod;
        end;
    pow[0]:=1;
    for i:=1 to max(n,m) do
        pow[i]:=(pow[i-1]*seed)mod mmod;
    i:=1; j:=1;
    while (i<=n)and(j<=m) do
        begin
            tt:=query(i,j);
            if y[i+tt]<z[j+tt]
            then begin write(y[i],' '); inc(i); end
            else begin write(z[j],' '); inc(j); end;
        end;
    for k:=i to n do
        write(y[k],' ');
    for k:=j to m do
        write(z[k],' ');
    writeln;
end.

你可能感兴趣的:([BZOJ4278] [ONTAK2015]Tasowanie)