• poj3378


    统计长度为5的上升序列个数,

    容易想到O(n^2)的dp

    f[k,i]:=Σf[k-1,j] (1<=j<i,a[i]>a[j])

    ans:=Σf[5,i] 

    但是显然会超时,需要考虑优化

    怎样快速找到所有比当前高度小的状态的和呢?

    答案很显然:树状数组

    考虑到这题每个数<=10^9,我们要将其离散化,再映射到树状数组上

    注意这题的最终答案爆int64,所以要用到高精度

     1 var f,tr:array[0..5,0..50010] of int64; //tr[i,j]表示树状数组,序列长度为i时,末尾离散化后高度为j;树状数组不会爆int64
     2     ans,d:array[0..100] of integer;
     3     a,b,c:array[0..50010] of longint;
     4     len,k,n,i,j:longint;
     5 
     6 function lowbit(x:longint):longint;
     7   begin
     8     exit(x and (-x));
     9   end;
    10 
    11 procedure add(z:int64);       //高精度加法
    12   var i,la,w,x:longint;
    13   begin
    14     fillchar(d,sizeof(d),0);
    15     la:=0;
    16     while z<>0 do
    17     begin
    18       la:=la+1;
    19       d[la]:=z mod 10;
    20       z:=z div 10;
    21     end;
    22     if la>len then len:=la;
    23     inc(len);
    24     w:=0;
    25     for i:=1 to len do
    26     begin
    27       x:=w+d[i]+ans[i];
    28       ans[i]:=x mod 10;
    29       w:=x div 10;
    30     end;
    31     if ans[len]=0 then dec(len);
    32   end;
    33 
    34 function sum(p,q:longint):int64;
    35   begin
    36     sum:=0;
    37     while p>0 do
    38     begin
    39       sum:=sum+tr[q,p];
    40       p:=p-lowbit(p);
    41     end;
    42   end;
    43 
    44 procedure work(p,q,z:int64);   //将当前状态加入树状数组
    45   begin
    46     while p<=n do
    47     begin
    48       tr[q,p]:=tr[q,p]+z;
    49       p:=p+lowbit(p);
    50     end;
    51   end;
    52 
    53 begin
    54   while not eof do
    55   begin
    56     readln(n);
    57     fillchar(c,sizeof(c),0);
    58     fillchar(tr,sizeof(tr),0);
    59     fillchar(f,sizeof(f),0);
    60     for i:=1 to n do
    61     begin
    62       read(a[i]);
    63       b[i]:=i;
    64     end;
    65     readln;
    66     sort(1,n);
    67     c[b[1]]:=1;
    68     k:=1;
    69     for i:=2 to n do    //离散化,注意重复的标相同的号
    70       if a[i]=a[i-1] then
    71         c[b[i]]:=c[b[i-1]]
    72       else begin
    73         inc(k);
    74         c[b[i]]:=k;
    75       end;
    76     fillchar(ans,sizeof(ans),0);
    77     len:=1;
    78     for i:=1 to n do
    79     begin
    80       f[1,i]:=1;
    81       work(c[i],1,1);
    82       for j:=2 to 5 do
    83       begin
    84         f[j,i]:=sum(c[i]-1,j-1);    //dp
    85         if f[j,i]>0 then work(c[i],j,f[j,i]);  
    86       end;
    87       if f[5,i]>0 then add(f[5,i]);
    88     end;
    89     for i:=len downto 1 do
    90       write(ans[i]);
    91     writeln;
    92   end;
    93 end.
    View Code

    总复杂度为O(nlogn)

    质量很高的一道题

    var f,tr:array[0..5,0..50010] of int64; //tr[i,j]表示树状数组,序列长度为i时,末尾离散化后高度为j;树状数组不会爆int64

        ans,d:array[0..100] of integer;

        a,b,c:array[0..50010] of longint;

        len,k,n,i,j:longint;

     

    function lowbit(x:longint):longint;

      begin

        exit(x and (-x));

      end;

     

    procedure add(z:int64);       //高精度加法

      var i,la,w,x:longint;

      begin

        fillchar(d,sizeof(d),0);

        la:=0;

        while z<>0 do

        begin

          la:=la+1;

          d[la]:=z mod 10;

          z:=z div 10;

        end;

        if la>len then len:=la;

        inc(len);

        w:=0;

        for i:=1 to len do

        begin

          x:=w+d[i]+ans[i];

          ans[i]:=x mod 10;

          w:=x div 10;

        end;

        if ans[len]=0 then dec(len);

      end;

     

    function sum(p,q:longint):int64;

      begin

        sum:=0;

        while p>0 do

        begin

          sum:=sum+tr[q,p];

          p:=p-lowbit(p);

        end;

      end;

     

    procedure work(p,q,z:int64);   //将当前状态加入树状数组

      begin

        while p<=n do

        begin

          tr[q,p]:=tr[q,p]+z;

          p:=p+lowbit(p);

        end;

      end;

     

    begin

      while not eof do

      begin

        readln(n);

        fillchar(c,sizeof(c),0);

        fillchar(tr,sizeof(tr),0);

        fillchar(f,sizeof(f),0);

        for i:=1 to n do

        begin

          read(a[i]);

          b[i]:=i;

        end;

        readln;

        sort(1,n);

        c[b[1]]:=1;

        k:=1;

        for i:=2 to n do    //离散化,注意重复的标相同的号

          if a[i]=a[i-1] then

            c[b[i]]:=c[b[i-1]]

          else begin

            inc(k);

            c[b[i]]:=k;

          end;

        fillchar(ans,sizeof(ans),0);

        len:=1;

        for i:=1 to n do

        begin

          f[1,i]:=1;

          work(c[i],1,1);

          for j:=2 to 5 do

          begin

            f[j,i]:=sum(c[i]-1,j-1);    //dp

            if f[j,i]>0 then work(c[i],j,f[j,i]);  

          end;

          if f[5,i]>0 then add(f[5,i]);

        end;

        for i:=len downto 1 do

          write(ans[i]);

        writeln;

      end;

    end.

     

  • 相关阅读:
    [充电]多线程无锁编程--原子计数操作:__sync_fetch_and_add等12个操作
    [转]架构、框架、模式、模块、组件、插件、控件、中间件的含义
    [网络]网络爬虫
    PHP时间戳和日期转换
    两个input之间有空隙,处理方法
    去除输入框原始效果【原创】
    php做图片上传功能
    PHP获取随机数的函数rand()和mt_rand()
    PHP简单的图片上传
    基于layui的表格异步删除,ajax的简单运用
  • 原文地址:https://www.cnblogs.com/phile/p/4473285.html
Copyright © 2020-2023  润新知