NOIP2016全国信息学分区联赛提高组第二试 蚯蚓

本题通过构建单调队列模拟蚯蚓的增长与切割过程,玩家需处理蚯蚓长度的变化及输出特定时间点的数据。

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

【问题描述】

本题中,我们将用符号 LcJ 表示对 c 向下取整,例如: L3.0J = L3.1J = L3.9J = 3。   蛐蛐国最近蚯蚓成灾了!隔壁跳蚤国的跳蚤也拿蚯蚓们没办法,蛐蛐国王只好去请神刀手来帮他们消灭蚯蚓。    蛐蛐国里现在共有 n 只蚯蚓( n 为正整数)。每只蚯蚓拥有长度,我们设第 i 只蚯蚓的长度为 ai ( i = 1, 2, . . . , n ),并保证所有的长度都是非负整数(即:可能存在长度为0的蚯蚓)。

蛐蛐国王当然知道怎么做啦! 但是他想考考你……
【输入格式】

从文件 earthworm.in 中读入数据。
第一行包含六个整数 n, m, q, u, v, t ,其中: n, m, q 的意义见【问题描述】; u, v, t 均 为正整数;你需要自己计算 p = u/v (保证 0 < u < v );t 是输出参数,其含义将会在【输出格式】中解释。    
第二行包含 n 个非负整数,为 a1, a2, . . . , an ,即初始时 n 只蚯蚓的长度。    同一行中相邻的两个数之间,恰好用一个空格隔开。   保证 1 ≤ n ≤ 105 , 0 ≤ m ≤ 7 × 106 , 0 < u < v ≤ 109 , 0 ≤ q ≤ 200 , 1 ≤ t ≤ 71 , 0 ≤ ai ≤ 108 。      

【输出格式】

 输出到文件 earthworm.out    第一行输出 个整数,按时间顺序,依次输出第 t秒,第 2t 秒,第 3t 秒,......被切 断蚯蚓(在被切断前)的长度。第二行输出个整数,输出 m 秒后蚯蚓的长度:需要按从大到小的顺序,依次输出排名第 t ,第 2t ,第 3t ,. . . . . . 的长度。    同一行中相邻的两个数之间,恰好用一个空格隔开。即使某一行没有任何数需要输出,你也应输出一个空行。    请阅读样例来更好地理解这个格式。

题解

我们构建3个单调队列,分别记为q[0],q[1],q[2]。其中q[0]记录初始时每条蚯蚓的长度,并将其按从大到小的顺序排列。q[1]记录每次切割后长的那一截的长度。q[2]记录每次切割后短的那一截的长度。对于蚯蚓增长的长度,我们可以运用标记的思想,因为每条蚯蚓所增长的长度都是一样的。
显然,这样子构出来的3个队列都是单调递减的,于是每次切割,取3个队列队首最大的元素进行切割,假设它的大小为x,当前增长长度为l,每单位时间蚯蚓长度增长L。那么,这条蚯蚓的长度len=x+l,切割后长度记为l1和l2,那么放入队列时将l1和l2都减去L+l,这样它们就可以和整个队列中的元素的标记同步了。
需要输出的时候判断一下当前的时间是否是t的倍数即可。

代码

type
  arr=array [1..3] of longint;
var
  gg:boolean;
  n,m,q,u,v,tn:longint;
  l,r:arr;
  a:array [1..3,0..10000001] of int64;
procedure qsort(l,r:longint);
var
  i,j:longint;
  mid,t:int64;
begin
  if l>r then exit;
  i:=l; j:=r;
  mid:=a[1,(i+j) div 2];
  repeat
    while a[1,i]>mid do inc(i);
    while a[1,j]<mid do dec(j);
    if i<=j then
      begin
        t:=a[1,i]; a[1,i]:=a[1,j]; a[1,j]:=t;
        t:=a[2,i]; a[2,i]:=a[2,j]; a[2,j]:=t;
        t:=a[3,i]; a[3,i]:=a[3,j]; a[3,j]:=t;
        inc(i); dec(j);
      end;
  until i>j;
  qsort(l,j);
  qsort(i,r);
end;

procedure init;
var
  i:longint;
begin
  readln(n,m,q,u,v,tn);
  for i:=1 to n+m do
    begin
      a[1,i]:=-maxlongint;
      a[2,i]:=-maxlongint;
      a[3,i]:=-maxlongint;
    end;
  for i:=1 to n do
    read(a[1,i]);
  qsort(1,n); gg:=false;
end;

procedure main;
var
  i,j,k:longint;
  max,x,y,tk,t:int64;
begin
  l[1]:=1; r[1]:=n;
  l[2]:=1; r[2]:=0;
  l[3]:=1; r[3]:=0;
  for i:=1 to m do
    begin
      max:=-maxlongint;
      for j:=1 to 3 do
        if a[j,l[j]]>max then
          begin
            max:=a[j,l[j]];
            k:=j;
          end;
      t:=max+(i-1)*q;
      inc(l[k]);
      if i mod tn=0 then
        begin
          write(t,' ');
        end;
      x:=trunc(t*u/v); y:=trunc(t-x);
      if x<y then
        begin
          tk:=x; x:=y; y:=tk;
        end;
      inc(r[2]); a[2,r[2]]:=x-i*q;
      inc(r[3]); a[3,r[3]]:=y-i*q;
    end;
  writeln;
end;

procedure print;
var
  i,j,k:longint;
  max,t:int64;
begin
  for i:=1 to n+m do
    begin
      max:=-maxlongint;
      for j:=1 to 3 do
        if a[j,l[j]]>max then
          begin
            max:=a[j,l[j]];
            k:=j;
          end;
      t:=max+m*q;
      inc(l[k]);
      if i mod tn=0 then write(t,' ');
    end;
end;

begin
  init;
  main;
  print;
end.
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值