【NOIP2016提高A组模拟9.7】千帆渡

题目

Description
【NOIP2016提高A组模拟9.7】千帆渡_第1张图片
Input
这里写图片描述
Sample Input

输入1:
5
1 4 2 5 1
4
1 1 2 4
Output
这里写图片描述
Sample Output

输出1:
2
1 4

比赛时の想法

暴力加一点点小优化,没有拍结果错了QAQ

玄学!!!

这一道题的暴力版本dp显然是枚举4个位置,然后转移,下面我们一个个找优化!
我们设4个位置分别为a[i],a[k],b[j],b[l](由(k,l)–>(i,j))
1:我们可以发现a[i]=b[j],a[k]=b[l]时才可能可以转移,所以我们先离散化一下,然后把值相等的都放到一个数组s中,数组里面记录这个值每一次出现的位置
2:我们可以发现如果有a[i]=a[i+1],或b[i]=b[i+1],那么我们可以合并这两个位置
3:我们可以把s数组中对每一种树位置的存储排一次序,然后把j从1->s[a[i],0]枚举一下,那么每一次j的值都会变大,那么我们存储每一次运算完之后的cy(cy表示最后一次转移方程l的位置),那么下一次做的时候l的位置就可以从cy开始了
到这里我们的dp已经是稳定 O(N3) ,大部分情况都是 O(N2) 的了!
那么怎么样的数据可以在这种情况下卡掉我们呢?
对于大部分a[i]<>a[i-1],b[i]<>b[i-1],而且离散化只有大概有500多个数
4:最后一个玄学优化!我们贪心的想,每次枚举k位置的时候,如果a[k]的值已经出现过了,那么肯定是选后面的更优,所以我们倒着枚举k的位置,并且用一个布尔数组判重就可以了
**事实证明,这个玄学算法水法很牛逼,而且卡不掉(而且比一些打的不好的正解还要快~)!

贴代码

其实这个方法就是代码长了一点点

var
    a,b,c,d:array[0..5005]of longint;
    h:array[0..5005]of longint;
    bz:array[0..5005]of boolean;
    f,s,g,p:array[0..5005,0..5005]of longint;
    i,j,k,l,n,m,x,y,ans,r,mid,cy:longint;
    yjk:boolean;
procedure qsort(l,r:longint);
var
    i,j,mid:longint;
begin
    i:=l;
    j:=r;
    mid:=c[(i+j) div 2];
    repeat
        while c[i]do inc(i);
        while c[j]>mid do dec(j);
        if i<=j then
        begin
            c[0]:=c[i];
            c[i]:=c[j];
            c[j]:=c[0];
            inc(i);
            dec(j);
        end;
    until i>j;
    if ithen qsort(i,r);
    if lthen qsort(l,j);
end;
function max(x,y:longint):longint;
begin
    if xthen
    begin
        g[i,s[a[i],j]]:=k;
        p[i,s[a[i],j]]:=s[a[k],l];
        cy:=l;
        exit(y);
    end else exit(x);
end;
procedure qsort1(l,r,x:longint);
var
    i,j,mid:longint;
begin
    i:=l;
    j:=r;
    mid:=s[x,(i+j) div 2];
    repeat
        while s[x,i]do inc(i);
        while s[x,j]>mid do dec(j);
        if i<=j then
        begin
            s[0,0]:=s[x,i];
            s[x,i]:=s[x,j];
            s[x,j]:=s[0,0];
            inc(i);
            dec(j);
        end;
    until i>j;
    if ithen qsort1(i,r,x);
    if lthen qsort1(l,j,x);
end;
procedure init;
begin
    assign(input,'t2.in'); reset(input);
    readln(n);
    for i:=1 to n do read(a[i]);
    readln;
    readln(m);
    for i:=1 to m do read(b[i]);
    readln;
    c:=a;
    qsort(1,n);
    l:=1;
    h[1]:=c[1];
    for i:=2 to n do
    if c[i]<>c[i-1] then
    begin
        inc(l);
        h[l]:=c[i];
    end;
    c:=h;
    x:=0;
    for i:=1 to n do
        for j:=1 to l do
            if c[j]=a[i] then
            begin
                a[i]:=j;
                break;
            end;
    for i:=n downto 2 do
    if a[i]=a[i-1] then
    begin
        for j:=i to n-1 do a[j]:=a[j+1];
        inc(x);
    end;
    n:=n-x;
    for i:=1 to m do
        for j:=1 to l do
            if b[i]=c[j] then
            begin
                b[i]:=j;
                bz[i]:=true;
                break;
            end;
    x:=0;
    for i:=m downto 1 do
    if bz[i]=false then
    begin
        for j:=i+1 to m do b[j-1]:=b[j];
        inc(x);
    end;
    m:=m-x;
    for i:=1 to m do
    begin
        inc(s[b[i],0]);
        s[b[i],s[b[i],0]]:=i;
    end;
end;
begin
    init;
    for i:=1 to l do qsort1(1,s[i,0],i);
    s[0,0]:=1;
    s[0,1]:=0;
    mid:=l;
    for i:=1 to n do
    begin
        fillchar(bz,sizeof(bz),false);
        for k:=i-1 downto 0 do
        if bz[a[k]]=false then
        begin
            bz[a[k]]:=true;
            x:=1;
            cy:=0;
            if a[k]then
            for j:=1 to s[a[i],0] do
            begin
                for l:=x to s[a[k],0] do
                if s[a[i],j]>s[a[k],l] then
                begin
                    f[i,s[a[i],j]]:=max(f[i,s[a[i],j]],f[k,s[a[k],l]]+1);
                end else break;
                x:=l;
                l:=cy;
                if l>0 then
                f[i,s[a[i],j]]:=max(f[i,s[a[i],j]],f[k,s[a[k],l]]+1);
                if f[i,s[a[i],j]]=mid then yjk:=true;
                if yjk then break;
            end;
            if yjk then break;
        end;
        if yjk then break;
    end;
    for i:=n downto 1 do
    for j:=1 to m do
    if f[i,j]>ans then
    begin
        ans:=f[i,j];
        x:=i;
        y:=j;
    end;
    l:=0;
    b:=h;
    fillchar(h,sizeof(h),0);
    while x>0 do
    begin
        inc(l);
        h[l]:=x;
        i:=g[x,y];
        j:=p[x,y];
        x:=i;
        y:=j;
    end;
    writeln(ans);
    for i:=l downto 1 do write(b[a[h[i]]],' ');
    writeln;
    close(input);
end.

你可能感兴趣的:(DP)