jzoj P1542 【USACO Open 2012银】跑步Running laps

题目描述

FJ觉得赛马很无聊,于是决定调查将赛牛作为一种运动的可能性。他安排了N(1 <= N <= 100,000)头奶牛来进行一个L圈的赛牛比赛,比赛在一个环形的长度为C的跑道上进行。所有的奶牛在跑道上的同一个点出发,每头奶牛的速度不同,当最快的奶牛跑完L*C的距离后结束。

FJ注意到了一头奶牛超过另一头奶牛这种情况的发生,并且他想知道这种“超车事件”在整个比赛中发生了多少次。更明确地,一次超车事件被定义为一对奶牛(x, y)和一个时刻t(小于等于结束时刻),且t时刻奶牛x超越到了奶牛y的前面,请帮助FJ计算整个比赛过程中“超车事件”发生的次数。

输入

第1行,3个空格隔开的整数N、L、C(1 <= L,C <= 25,000)

第2行至第n + 1行,第i + 1行有一个整数,表示第i个奶牛的速度,范围在1..1000000之间

输出

超车总数

样例输入

4 2 100

20

100

70

1

样例输出

4

题解:
1.把所有速度从大到小排序。
2.用 路程/最快的速度 算出比赛持续时间t。
3.把每一个奶牛在t时间内能跑多少圈求出来,然后分别储存整数跟小数部分。
4.用公式把每一只奶牛整数部分圈数对答案的贡献求出。
5.归并排序求出小数部分的逆序对数量,减去,因为有类似 1.50 跟 2.49取整是没有一圈的,注意精度问题,不然会WA。

var
   a,s:array [0..100001] of longint;
   t,p:array [0..100001] of extended;
   i,n,l,c:longint;
   ans,h,j:int64;

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

procedure merge(l,r:longint);
var
        mid,i,j,k:longint;
begin
        if l=r then exit;
        mid:=(r+l) div 2;
        merge(l,mid);
        merge(mid+1,r);
        i:=l;
        j:=mid+1;
        k:=l;
        while (i<=mid) and (j<=r) do
               begin
                  if t[i]-t[j]>-0.0000001
                     then begin
                            p[k]:=t[i];
                            inc(i);
                          end
                     else begin
                            p[k]:=t[j];
                            inc(j);
                            inc(h,mid-i+1);
                          end;
                  inc(k);
               end;
               while i<=mid do
                     begin
                        p[k]:=t[i];
                        inc(i);
                        inc(k);
                     end;
                     while j<=r do
                           begin
                             p[k]:=t[j];
                             inc(j);
                             inc(k);
                           end;
        for i:=l to r do t[i]:=p[i];
end;


begin
    assign(input,'running.in');   reset(input);
    assign(output,'running.out'); rewrite(output);
        readln(n,l,c);
        for i:=1 to n do readln(a[i]);
        qsort(1,n);
        t[0]:=l*c/a[1];
        for i:=1 to n do
            begin
               s[i]:=trunc(a[i]*t[0]/c);
               t[i]:=a[i]*t[0]/c-s[i];
            end;
        merge(1,n);
        for i:=n downto 1 do
            begin
                j:=j+(n-i)*(s[i]-s[i+1]);
                ans:=ans+j;
            end;
       writeln(ans-h);
  close(input); close(output);
end.
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值