Noi 2010 day1 第二题 超级钢琴

5 篇文章 0 订阅
3 篇文章 0 订阅

题目:

 超级钢琴

来源:

 Noi 2010 day1 第二题

题目大意:

 N个数,求K个长度大于L小于R的序列(每个序列为连续数的和),且每个序列元素  不能完全相同,求最大值

数据范围:

 N<=500000,K<=500000

样例:

 4 3 2 3

 3

 2

 -6

 8

11

做题思路:

 怎么说呢,rmq+堆(大牛教的)。

 Rmq用来找区间最大,把它记录在堆中,然后求出以该最大为边界的序列权值和,  维护堆,并由此插入该最大删除后的次大,然后就去k个数呗,over

 还有一个20分的代码,就是朴素的算出所有满足要求的序列和,然后排序,输出

 有一个样例是K=1的,能不能动归10分呢?

知识点:

RMQ(st,线段树),堆,二分求次大

const
 MaxN=500010;
type
 node=record
    start,l,r,hmax,val:longint;{<开始,结束端的左右边界,最大点,权值和>}
 end;
var
 n,le,re,k,heaptot:longint;
 a,sum:array[0..MaxN] of longint;
 f:array[0..MaxN,0..30] of longint;
 heap:array[0..MaxN*2] of node;
 ans:int64;
procedure init;
 var
    i:longint;
 begin
    read(n,k,le,re);
    for i:=1 to n do
    begin
      read(a[i]);
      sum[i]:=sum[i-1]+a[i];{<求从1开始的和>}
    end;
 end;
function max(x,y:longint):longint;
 begin
    if sum[x]>sum[y] then exit(x) elseexit(y);
 end;
procedure st;{<rmq问题初始化>}
 var
    i,j,t:longint;
 begin
    for i:=1 to n do f[i,0]:=i;
    t:=trunc(ln(n)/ln(2));
    for j:=1 to t do
      for i:=1 to n-(1 shl j)+1 do
        f[i,j]:=max(f[i,j-1],f[i+(1 shl(j-1)),j-1]);
 end;
procedure swap(var x,y:node);
 var
    tmp:node;
 begin
    tmp:=x; x:=y; y:=tmp;
 end;
procedure up(now:longint);{<上调>}
 begin
    while now>1 do
    if (heap[now].val>heap[now shr 1].val)then
    begin
      swap(heap[now],heap[now shr 1]);
      now:=now shr 1;
    end else exit;
 end;
procedure down(now:longint);{<下调>}
 var
    tmp:longint;
 begin
    while now shl 1<=heaptot do
    begin
      if (now shl 1=heaptot) or (heap[now shl1].val>heap[(now shl 1)+1].val)
      then tmp:=now shl 1 else tmp:=(now shl1)+1;
      if heap[tmp].val>heap[now].val then
      begin
        swap(heap[tmp],heap[now]);
        now:=tmp;
      end
      else exit;
    end;
 end;
procedureinsert(i,ll,rr:longint);{<插入堆>}
 var
    tmp:longint;
 begin
    if rr>n then rr:=n;{<超出最大右边界则修改右边界>}
    inc(heaptot);
    with heap[heaptot] do{<with,对记录型内直接操作>}
    begin
      start:=i; l:=ll; r:=rr;
      tmp:=trunc(ln(r-l+1)/ln(2));{<st>}
      hmax:=max(f[l,tmp],f[r-(1 shltmp)+1,tmp]);
      val:=sum[hmax]-sum[start-1];
    end;
    up(heaptot);
 end;
procedure main;
 var
    i,tstart,tl,tr,tmax:longint;
 begin
    heaptot:=0;
    for i:=1 to n do{<以i为左边界插入>}
    begin
      if i+le-1>n then break;{<左边界到最大右边界的距离<le,说明不符合要求>}
      insert(i,i+le-1,i+re-1);{<插入所有的最大>}
    end;
    for i:=1 to k do
    begin
      ans:=ans+heap[1].val;{<累加答案>}
      with heap[1] do
      begin
        tstart:=start;
        tl:=l;
        tr:=r;
        tmax:=hmax;
      end;
      heap[1]:=heap[heaptot];
      dec(heaptot);
      down(1);
      if tmax>tl theninsert(tstart,tl,tmax-1);{<这个值插入后,修改其右边界,继续插入,导致次大>}
      if tmax<tr theninsert(tstart,tmax+1,tr);
    end;
 end;
begin
 assign(intput,'piano.in');reset(input);
 assign(output,'piano.out');rewrite(output);
 init;
 st;
 ans:=0;
 main;
 writeln(ans);
 close(input);close(output);
end.
题目来源: http://www.tyvj.cn:8080/Problem_Show.asp?id=1256

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
大学生参加学科竞赛有着诸多好处,不仅有助于个人综合素质的提升,还能为未来职业发展奠定良好基础。以下是一些分析: 首先,学科竞赛是提高专业知识和技能水平的有效途径。通过参与竞赛,学生不仅能够深入学习相关专业知识,还能够接触到最新的科研成果和技术发展趋势。这有助于拓展学生的学科视野,使其对专业领域有更深刻的理解。在竞赛过程中,学生通常需要解决实际问,这锻炼了他们独立思考和解决问的能力。 其次,学科竞赛培养了学生的团队合作精神。许多竞赛项目需要团队协作来完成,这促使学生学会有效地与他人合作、协调分工。在团队合作中,学生们能够学到如何有效沟通、共同制定目标和分工合作,这对于日后进入职场具有重要意义。 此外,学科竞赛是提高学生综合能力的一种途径。竞赛项目通常会涉及到理论知识、实际操作和创新思维等多个方面,要求参赛者具备全面的素质。在竞赛过程中,学生不仅需要展现自己的专业知识,还需要具备创新意识和解决问的能力。这种全面的综合能力培养对于未来从事各类职业都具有积极作用。 此外,学科竞赛可以为学生提供展示自我、树立信心的机会。通过比赛的舞台,学生有机会展现自己在专业领域的优势,得到他人的认可和赞誉。这对于培养学生的自信心和自我价值感非常重要,有助于他们更加积极主动地投入学习和未来的职业生涯。 最后,学科竞赛对于个人职业发展具有积极的助推作用。在竞赛中脱颖而出的学生通常能够引起企业、研究机构等用人单位的关注。获得竞赛奖项不仅可以作为个人履历的亮点,还可以为进入理想的工作岗位提供有力的支持。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值