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

来源:互联网 发布:数据库快速开发平台 编辑:程序博客网 时间:2024/05/16 02:01

题目

Description
这里写图片描述
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]<mid 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 i<r then qsort(i,r);    if l<j then qsort(l,j);end;function max(x,y:longint):longint;begin    if x<y then    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]<mid 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 i<r then qsort1(i,r,x);    if l<j then 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]<a[i] 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.
1 0
原创粉丝点击