zoukankan      html  css  js  c++  java
  • NOIP2015普及组T4推销员(暴力+线段树)

          题目:阿明是一名推销员,他奉命到螺丝街推销他们公司的产品。螺丝街是一条死胡同,出口与入口是同一个,街道的一侧是围墙,另一侧是住户。螺丝街一共有N家住户,第i家住户到入口的距离为Si米。由于同一栋房子里可以有多家住户,所以可能有多家住户与入口的距离相等。阿明会从入口进入,依次向螺丝街的X家住户推销产品,然后再原路走出去。
          阿明每走1米就会积累1点疲劳值,向第i家住户推销产品会积累Ai点疲劳值。阿明是工作狂,他想知道,对于不同的X,在不走多余的路的前提下,他最多可以积累多少点疲劳值

    输入格式:
    第一行有一个正整数N,表示螺丝街住户的数量。
    接下来的一行有N个正整数,其中第i个整数Si表示第i家住户到入口的距离。数据保证S1≤S2≤…≤Sn<10^8。
    接下来的一行有N个正整数,其中第i个整数Ai表示向第i户住户推销产品会积累的疲劳值。数据保证Ai<10^3。
    输出格式:
    输出N行,每行一个正整数,第i行整数表示当X=i时,阿明最多积累的疲劳值。

    【数据说明】
    对于20%的数据,1≤N≤20;
    对于40%的数据,1≤N≤100;
    对于60%的数据,1≤N≤1000;
    对于100%的数据,1≤N≤1000000。

          NOIP之前一直以为NOIP不会考线段树(其实真的没考,这题正解是贪心但是我不会%%%),所以写T4的时候打完暴力根本就没想到写线段树。暴力思路为一重循环枚举推销多少家,第二重循环找出消耗疲劳值最大的,然后改为0,输出答案,效率O(n^2)。

    暴力代码如下:

    var
      len,tired:array[0..1000000]of longint;
      n,i,j,max,s,ans,now,t,sum:longint;
    
    begin
      readln(n);
      for i:=1 to n do read(len[i]);
      for i:=1 to n do read(tired[i]);
      ans:=0;
      max:=0;
      for i:=1 to n do
      begin
        max:=-maxlongint;
        for j:=1 to n do
        begin
          if j>now then s:=(2*len[j])-(2*sum)+tired[j]
          else s:=tired[j];
          if s>max then
          begin
            t:=j;
            max:=s;
          end;
        end;
        if t>now then
        begin
          now:=t;
          sum:=len[now];
        end;
        len[t]:=0;tired[t]:=0;
        inc(ans,max);
        writeln(ans);
      end;
    end.
    View Code

          然后我们可以发现我们找最大值效率是O(n),那我们就用线段树来维护最大值就行了,效率O(log(n)),则总时间效率为O(nlog(n))。

          这里简单说一下思路。建两棵线段树,对于现在走到的点,一棵维护左边的疲劳值最大值,也就是只需要维护推销的疲劳值最大值,一棵维护右边的疲劳值最大值,需要维护推销的疲劳值+走路的疲劳值。

    代码如下(3kb):

    type
      point=record
        max,delta,l,r,num:longint;
      end;
    var
      len,tired:array[0..1000000]of int64;
      i,j:longint;
      n,max,ans,now,tt,t1,t2,max2,l,x,y:int64;
      a:array[0..1000000,1..2]of point;
    
    procedure insert(x,num,delta,t:longint);
    begin
      if a[x,t].l=a[x,t].r then a[x,t].max:=0
      else
      begin
        if num<=(a[x,t].l+a[x,t].r)>>1 then insert(2*x,num,delta,t);
        if num>(a[x,t].l+a[x,t].r)>>1 then insert(2*x+1,num,delta,t);
        if a[2*x,t].max>a[2*x+1,t].max then
        begin
          a[x,t].max:=a[2*x,t].max;
          a[x,t].num:=a[2*x,t].num;
        end
        else
        begin
          a[x,t].max:=a[2*x+1,t].max;
          a[x,t].num:=a[2*x+1,t].num;
        end;
      end;
    end;
    
    procedure build(x,l,r,t:longint);
    begin
      a[x,t].l:=l;a[x,t].r:=r;
      if l=r then
      begin
        a[x,t].num:=l;
        read(a[x,t].max);
        a[x,t].delta:=0;
        if t=1 then len[l]:=a[x,t].max;
        if t=2 then tired[l]:=a[x,t].max;
      end
      else
      begin
        build(2*x,l,(l+r)>>1,t);
        build(2*x+1,((l+r)>>1)+1,r,t);
        if a[2*x,t].max>a[2*x+1,t].max then
        begin
          a[x,t].max:=a[2*x,t].max;
          a[x,t].num:=a[2*x,t].num;
        end
        else
        begin
          a[x,t].max:=a[2*x+1,t].max;
          a[x,t].num:=a[2*x+1,t].num;
        end;
        a[x,t].delta:=0;
      end;
    end;
    
    procedure update(x,l,r,delta,t:longint);
    begin
      if (l<=a[x,t].l)and(a[x,t].r<=r) then
      inc(a[x,t].delta,delta)
      else
      begin
        if l<=(a[x,t].l+a[x,t].r)>>1 then update(2*x,l,r,delta,t);
        if r>(a[x,t].l+a[x,t].r)>>1 then update(2*x+1,l,r,delta,t);
        if a[2*x,t].max+a[2*x,t].delta>a[2*x+1,t].max+a[2*x+1,t].delta then
        begin
          a[x,t].max:=a[2*x,t].max+a[2*x,t].delta;
          a[x,t].num:=a[2*x,t].num;
        end
        else
        begin
          a[x,t].max:=a[2*x+1,t].max+a[2*x+1,t].delta;
          a[x,t].num:=a[2*x+1,t].num;
        end;
      end;
    end;
    
    function query(x,l,r,h,t:longint):int64;
    var
      ret:int64;
    begin
      ret:=0;
      if (l<=a[x,t].l)and(a[x,t].r<=r) then
      begin
        ret:=a[x,t].max+a[x,t].delta;
        if ret>=h then
        tt:=a[x,t].num;
      end
      else
      begin
        inc(a[2*x,t].delta,a[x,t].delta);
        inc(a[2*x+1,t].delta,a[x,t].delta);
        inc(a[x,t].max,a[x,t].delta);
        a[x,t].delta:=0;
        if l<=(a[x,t].l+a[x,t].r)>>1 then ret:=query(2*x,l,r,h,t);
        if r>(a[x,t].l+a[x,t].r)>>1 then
        if ret<query(2*x+1,l,r,ret,t) then ret:=query(2*x+1,l,r,ret,t);
      end;
      query:=ret;
    end;
    
    begin
      readln(n);
      build(1,1,n,1);
      build(1,1,n,2);
      for i:=1 to n do update(1,i,i,len[i]+tired[i],1);
      ans:=0;
      max:=0;
      tt:=0;
      for i:=1 to n do
      begin
        max:=-maxlongint;
        if now>0 then max:=query(1,1,now,0,2);
        t1:=tt;
        max2:=-maxlongint;
        if now<n then max2:=query(1,now,n,0,1);
        if max<max2 then
        begin
          max:=max2;
          t1:=tt;
        end;
        if t1>now then
        begin
          update(1,t1,n,-2*len[t1],1);
          insert(1,t1,0,1);
          now:=t1;
        end;
        insert(1,t1,0,2);
        inc(ans,max);
        writeln(ans);
      end;
    end.
    View Code

    以下为官方数据情况:

  • 相关阅读:
    findIndex() 方法用法
    Centos7安装nginx1.17.5,集成upstream和stream
    Centos7安装docker
    LeetCode(C++)刷题计划:17-电话号码的字母组合
    LeetCode(C++)刷题计划:16-最接近的三数之和
    LeetCode(C++)刷题计划:15-三数之和
    LeetCode(C++)刷题计划:14-最长公共前缀
    LeetCode(C++)刷题计划:13-罗马数字转整数
    LeetCode(C++)刷题计划:12-整数转罗马数字
    LeetCode(C++)刷题计划:11-盛最多水的容器
  • 原文地址:https://www.cnblogs.com/Sakits/p/5360703.html
Copyright © 2011-2022 走看看