海清's profileCockhorse BlogPhotosBlogListsMore Tools Help

Blog


    November 18

    noip2007

    今年的题太简单了,只要有一点小失误就死得很惨,自己觉得发挥得确实不好,不过分数还过得去,至少没和最高分差太多,选拔赛还是挺有希望的.
    November 12

    01背包前k优值(不一定装满)

    type
        ss=array[1..100]of longint;
    var
        f:array[0..10000]of ss;
        a,w:array[1..10000]of longint;
        v,i,j,n,k:longint;
    function max(a,b:ss;x:longint):ss;
    var
        i,j,l:longint;
        c:ss;
    begin
        i:=1;j:=1;l:=0;
        while l<k do
        begin
            inc(l);
            if a[i]<b[j]+x then
            begin
                c[l]:=b[j]+x;inc(j);
            end
            else
            begin
                c[l]:=a[i];inc(i);
            end;
        end;
        exit(c);
    end;
    begin
        read(k,v,n);
        for i:=1 to n do
            readln(a[i],w[i]);
        for i:=0 to v do
        for j:=1 to k do
            f[i,j]:=-maxlongint;
        f[0,1]:=0;
        for i:=1 to n do
        begin
            for j:=v downto a[i] do              {如果是完全背包则变成 for j:=a[i] to v 即可}
                f[j]:=max(f[j],f[j-a[i]],w[i]);
            for j:=a[i]+1 to v do                  {如果是"一定装满"则直接去掉此for语句即可}
                f[j]:=max(f[j],f[j-1],0);  
        end;
        for i:=1 to k do
        if f[v,i]<0 then break
        else write(f[v,i],' ');
        writeln;
    end.

    组合数C(n,r)

    递推式(不加高精,不加记忆化)

    var
        n,r:longint;
    function C(n,r:longint):longint;
    begin
        if (n=r)or(r=0) then exit(1)
        else exit(C(n-1,r-1)+C(n-1,r));
    end;
    begin
        readln(n,r);
        writeln(C(n,r));
    end.

    通项式-直接高精

    var
        a:array[0..100000]of integer;
        n,r,i,j,k,l,o:longint;
    begin
        readln(n,r);
        if r>n-r then r:=n-r;
        a[0]:=1;a[1]:=1;
        for i:=n-r+1 to n do
        begin
            k:=0;
            inc(a[0],trunc(ln(i)/ln(10))+1);
            for j:=1 to a[0] do
            begin
                o:=a[j]*i+k;
                a[j]:=o mod 10;
                k:=o div 10;
            end;
            while a[a[0]]=0 do dec(a[0]);
        end;
        for i:=2 to r do
        begin
            o:=0;
            for j:=a[0] downto 1 do
            begin
                o:=o*10+a[j];
                a[j]:=o div i;
                o:=o mod i;
            end;
            while a[a[0]]=0 do dec(a[0]);
        end;
        for i:=a[0] downto 1 do
            write(a[i]);
        writeln;
    end.

    通项式-分解质因数

    type
        ss=record
            i,x:longint;
        end;
    var
        h:array[1..100000]of boolean;
        g,f:array[1..100000]of ss;
        a:array[0..100000]of integer;
        r,i,j,k,l,n:longint;
        x,o:int64;
    function bp(b,p:longint):int64;
    var
        x:int64;
    begin
        if p=0 then exit(1)
        else
        begin
            x:=sqr(bp(b,p shr 1));
            if (p and 1)=1 then x:=x*b;
            exit(x);
        end;
    end;
    begin
        readln(n,r);
        if r>n-r then r:=n-r;
        l:=0;
        for i:=2 to n do
        if not h[i] then
        begin
            h[i]:=true;
            inc(l);f[l].i:=i;
            g[i].i:=i;g[i].x:=1;
            if i<=r then f[l].x:=-1
            else if i>n-r then f[l].x:=1;
            for j:=2 to n div i do
            begin
                h[j*i]:=true;
                g[j*i].i:=i;
                if g[j].i<>i then
                    g[j*i].x:=1
                else g[j*i].x:=g[j].x+1;
                if j*i<=r then dec(f[l].x,g[j*i].x)
                else if j*i>n-r then inc(f[l].x,g[j*i].x);
            end;
        end;
        a[0]:=1;a[1]:=1;
        for i:=1 to l do
        begin
            x:=bp(f[i].i,f[i].x);
            k:=0;
            inc(a[0],trunc(ln(x)/ln(10))+1);
            for j:=1 to a[0] do
            begin
                o:=a[j]*x+k;
                a[j]:=o mod 10;
                k:=o div 10;
            end;
            while a[a[0]]=0 do dec(a[0]);
        end;
        for i:=a[0] downto 1 do
            write(a[i]);
        writeln;
    end.

     

    November 11

    多重背包 O(V*Σlog n[i])

    把第i种物品换成n[i]件01背包中的物品,则得到了物品数为Σn[i]的01背包问题,直接求解,复杂度仍然是O(V*Σn[i])。

    方法:将第i种物品分成若干件物品,其中每件物品有一个系数,这件物品的费用和价值均是原来的费用和价值乘以这个系数。使这些系数分别为1,2,4,...,2^(k-1),n[i]-2^k+1,且k是满足n[i]-2^k+1>0的最大整数。例如,如果n[i]为13,就将这种物品分成系数分别为1,2,4,6的四件物品。

    01背包的最优方案总数

    for i=1..N
       for v=0..V
            f[i][v]=max{f[i-1][v],f[i-1][v-c[i]]+w[i]}
            g[i][v]=0
            if(f[i][v]==f[i-1][v])
                inc(g[i][v],g[i-1][v]
            if(f[i][v]==f[i-1][v-c[i]]+w[i])
                inc(g[i][v],g[i-1][v-c[i]])
    November 09

    01背包和完全背包 O(NV)

    01背包
    for i=1..N
        for v=V..0
            f[v]=max{f[v],f[v-c[i]]+w[i]};
    完全背包       
    for i=1..N
        for v=0..V
            f[v]=max{f[v],f[v-c[i]]+w[i]};

    LIS输出路径O(nlogn)

    type
        ss=record
            i,x:longint;
        end;
    var
        f:array[0..100000]of ss;
        a,b,c:array[1..100000]of longint;
        w,i,j,n:longint;
    function find(x,l,r:longint):longint;
    begin
        if l=r then
            if x>=f[l].x then
                 exit(l+1)
            else exit(l)
        else
            if x<f[(l+r)div 2].x then
                 exit(find(x,l,(l+r)div 2))
            else exit(find(x,(l+r)div 2+1,r));
    end;
    begin
        read(n);
        f[1].x:=maxlongint;w:=1;
        for i:=1 to n do
        begin
            read(a[i]);
            j:=find(a[i],1,w);
            f[j].x:=a[i];f[j].i:=i;b[i]:=f[j-1].i;
            if j>w then inc(w);
        end;
        writeln(w);
        i:=f[w].i;j:=0;
        while i<>0 do
        begin
            inc(j);c[j]:=a[i];
            i:=b[i];
        end;
        for i:=w downto 1 do
            write(c[i],' ');
        writeln;
    end.