poj3378

本文介绍了一种使用树状数组优化计数长度为5的上升序列的方法,通过离散化和高精度加法实现高效的计算。重点讨论了如何快速找到所有比当前高度小的状态和,以及如何利用树状数组进行状态更新和查询,最终得到答案。文章提供了详细的代码实现和复杂度分析,是一道高质量的算法优化题目。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

统计长度为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.

 

转载于:https://www.cnblogs.com/phile/p/4473285.html

内容概要:本文深入解析了扣子COZE AI编程及其详细应用代码案例,旨在帮助读者理解新一代低门槛智能体开发范式。文章从五个维度展开:关键概念、核心技巧、典型应用场景、详细代码案例分析以及未来发展趋势。首先介绍了扣子COZE的核心概念,如Bot、Workflow、Plugin、Memory和Knowledge。接着分享了意图识别、函数调用链、动态Prompt、渐进式发布及监控可观测等核心技巧。然后列举了企业内部智能客服、电商导购助手、教育领域AI助教和金融行业合规质检等应用场景。最后,通过构建“会议纪要智能助手”的详细代码案例,展示了从需求描述、技术方案、Workflow节点拆解到调试与上线的全过程,并展望了多智能体协作、本地私有部署、Agent2Agent协议、边缘计算插件和实时RAG等未来发展方向。; 适合人群:对AI编程感兴趣的开发者,尤其是希望快速落地AI产品的技术人员。; 使用场景及目标:①学习如何使用扣子COZE构建生产级智能体;②掌握智能体实例、自动化流程、扩展能力和知识库的使用方法;③通过实际案例理解如何实现会议纪要智能助手的功能,包括触发器设置、下载节点、LLM节点Prompt设计、Code节点处理和邮件节点配置。; 阅读建议:本文不仅提供了理论知识,还包含了详细的代码案例,建议读者结合实际业务需求进行实践,逐步掌握扣子COZE的各项功能,并关注其未来的发展趋势。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值