百团大战

31 篇文章 0 订阅
2 篇文章 0 订阅

题目描述
此百团大战非彼百团大战也。这指的是HYSBZ的社团开始招人了。若若的LMZ现在站在操场上,有很多很多个社团在操场上排成一排。有些社团为了吸引人们加入,会表演节目。而现在LMZ拿到了节目单,有n个节目,其描述了在Ti时刻Xi号社团会表演节目(持续时间忽略不计)。而LMZ在一单位时间内最多也只能跑过V个社团的距离(比如从1号社团跑到V+1号社团),而最少则可以不动,跑步的左右方向任意。他想知道:
1.当他初始时刻是站在0号社团的情况下,他最多能看到多少节目?
2.当他初始时刻可以站在任意位置的情况下,他最多能看到多少节目?
注:初始时刻指的是时间为0.
输入
第一行仅1个正整数n,为节目数量。
接下来n行每行2个正整数Xi,Ti,为第i个节目的属性。输入数据保证不会有重复的节目。
最后一行一个正整数V,表示LMZ的速度上限。
输出
仅2个正整数,分别为问题1和问题2的答案。
样例输入
3
6 1
1 3
4 4
4
样例输出
2 3
提示
[样例解释]

若一开始LMZ站在0号位置,那么在时间为1时是不可能跑到6号社团的,但是后面的2个表演可以看得到;而若一开始便站在6号社团处,便3个表演都看得到。

[数据范围与约定]
对于10%的数据:n<=10
对于40%的数据:n<=3000
对于100%的数据:1<=n<=100000,-2*108<=Xi<=2*108,1<=V<=1000,1<=Ti<=10^6

对于40%的数据,很容易想出DP算法,即f[i]表示刚看了第i场节目下最多看几场,则f[i]=max{f[j]+1},这个方程要满足:
1.Ti>Tj
2.(Ti-Tj)*v>=|xi-xj|
若要满足条件2,则必须要满足条件1,所以,条件1是无用的。那么我们把条件2拆开,得到:
1.Ti*v-xi>=Tj*v-xj
2.Ti*v+xi>=Tj*v+xj
于是我们只需按条件1排序,再按条件2做最长不下降子序列即可。至于两个询问的区别,请自行脑补。

var
n,i,v,l,r,mid,len,ans2,k:longint;
a,x,t,d:array[0..100011] of int64;
procedure sort(l,r:longint);
var
i,j,tt,m,mm:longint;
begin
  i:=l;j:=r;m:=a[(i+j) div 2]; mm:=t[(i+j) div 2]*v+x[(i+j) div 2];
  repeat
    while (a[i]<m)or((a[i]=m)and(t[i]*v+x[i]<mm))do inc(i);
    while (a[j]>m)or((a[j]=m)and(t[j]*v+x[j]>mm)) do dec(j);
    if i<=j then
    begin
      tt:=x[i];x[i]:=x[j];x[j]:=tt;
      tt:=t[i];t[i]:=t[j];t[j]:=tt;
      tt:=a[i];a[i]:=a[j];a[j]:=tt;
      inc(i);dec(j);
    end;
  until i>j;
  if i<r then sort(i,r);
  if j>l then sort(l,j);
end;

function max(a,b:longint):longint;
begin
  if a>b then exit(a) else exit(b);
end;

begin
  readln(n);
  for i:=1 to n do
  begin
    readln(x[i],t[i]);
  end;
  readln(v);
  for i:=1 to n do
    a[i]:=t[i]*v-x[i];
  sort(1,n);
  for i:=1 to n do
  begin
    a[i]:=t[i]*v+x[i];
    l:=0;
    r:=len;
    while l<>r do
    begin
      mid:=(l+r+1) div 2;
      if d[mid]<=a[i] then l:=mid
                      else r:=mid-1;
    end;
    l:=l+1;
    d[l]:=a[i];
    len:=max(len,l);
  end;
  ans2:=len;
  len:=0;
  for i:=1 to n do
    a[i]:=t[i]*v-x[i];
  sort(0,n);
  for i:=0 to n do
    if a[i]=0 then begin k:=i; break; end;
  for i:=k to n do
  begin
    a[i]:=t[i]*v+x[i];
    l:=0;
    r:=len;
    while l<>r do
    begin
      mid:=(l+r+1) div 2;
      if d[mid]<=a[i] then l:=mid
                      else r:=mid-1;
    end;
    l:=l+1;
    if (l=1)and(a[i]<>0) then continue;
    d[l]:=a[i];
    len:=max(len,l);
  end;
  write(len-1,' ',ans2);
end.
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值