绕圈跑*纪中*2390*数学方法/树状数组

题目大意

  Farmer John决定调查开展“奶牛赛跑运动”的可能性。   他将N头奶牛(1 <= N <= 100,000),放在一个长度为C的圆形跑道上。奶牛们沿圆形跑道,跑L圈。   所有奶牛起点都相同,跑步的速度不同。   当最快的奶牛跑完距离L*C的时候,比赛结束。   FJ注意到,有些时候一头奶牛会超过另一个奶牛。   他在思考,整个比赛中,这类“超车事件”会发生多少次。   更具体的说,一个“超车事件”指的是:   一对奶牛(x,y)和一个时间t(小于等于比赛结束时间),在时间t奶牛x超过前面的奶牛y。  请帮FJ计算整个比赛过程中,“超车事件”发生的次数。


分析

  又是他*2——olahiuj

  这道题我实在是不想说些什么了,自行理解。

  或着看——

 Let us define L(i) as the number of laps cow i performs until the race ends. For simplicity, we will think of L(i) as a real number, although in the implementation below we can manage to do all of our math in integers (always a good idea, to avoid round-off issues). If L(i) > L(j), then the number of times cow i crosses cow j is given by the floor of L(i)-L(j). Our goal is therefore to sum up floor(L(i)-L(j)) over all i>j (assuming the cows are ordered in increasing order of L(i)).

 If all we had to do was sum up L(i)-L(j) over all i>j, this would be easy: we would first precompute the prefix sums P(j)=L(1)+...+L(j), and then we can write the sum of L(i)-L(j) over all i>j as the sum of jL(i)-P(i) over all i; this can be therefore computed in linear time. The floor function is really the tricky aspect of this problem. To deal with this properly, we start by setting each L(i) to its floor, and by computing prefix sums as before. We then sum up jL(i)-P(i) over all i, but in increasing order of the fractional part of L(i). As we proceed, we add +1 to each L(i) we encounter (and adjust the prefix sums accordingly, using an appropriate data structure like a binary index tree). Travis' code below shows how to implement this idea.

                                                             -------致看懂的童鞋:请在评论中吱一声,谢谢。

代码
type
  arry=array[0..100010] of longint;
var
  d,num:array[0..100010] of longint;
  b:array[1..200010] of longint;
  i,j,k:longint;
  n,l,c:longint;
  ans:int64;

procedure qsort(var a:arry;l,r:longint);
var
  i,j,k:longint;
  mid:longint;
  temp:longint;
begin
  if (l>=r)
    then exit;
  i:=l; j:=r;
  mid:=a[(l+r) div 2];
  repeat
    while a[i]<mid do i:=i+1;
    while a[j]>mid do j:=j-1;
    if i<=j
      then
        begin
          temp:=a[i]; a[i]:=a[j]; a[j]:=temp;
          i:=i+1; j:=j-1;
        end;
  until i>j;
  qsort(a,l,j);
  qsort(a,i,r);
end;

procedure bian(p,c:longint);
begin
  while p<=d[n]+1 do
    begin
      b[p]:=b[p]+c;
      p:=p+(p and (p xor (p-1)));
    end;
end;

function tong(p:longint):longint;
begin
  tong:=0;
  while p>0 do
    begin
      tong:=tong+b[p];
      p:=p-(p and (p xor (p-1)));
    end;
end;
begin
  readln(n,l,c);
  for i:=1 to n do
    readln(d[i]);
  qsort(d,1,n);
  for i:=1 to n do
    begin
      j:=trunc(d[i]*l/d[n]);
      num[i]:=num[i-1]+j;
      k:=d[i]*l mod d[n];
      bian(k+1,1);
      ans:=ans+j*i-num[i]-i+tong(k+1);
    end;
  writeln(ans);
end.





  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值