SSL P2697 找礼物

本文介绍了一种基于排序和枚举的算法解决方法,用于计算玩家及其朋友在原点位置时,各自能获取的最近距离礼物的数量及详情。考虑了坐标精度及数据规模限制,并通过具体实现步骤和代码片段展示了解决方案。

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

题目大意:
你和你的K-1个好友的周围满是礼物,你发扬你帅气的风格,让你的好友先拿,你最后拿,每个人只能拿当前离自己最近的礼物(有多个距离相等的礼物可以全部拿走)(距离精确到小数后四位,所有运算均为去尾)。
大家都处于原点(0,0),给出每个礼物的坐标(x,y)以及是谁送的。要你找出你的礼物离你的距离D,你能拿到的礼物数量U,一次U个礼物分别是谁送的,按输入顺序输出。若拿不到礼物,则输出“555”。

对于30%的数据 K≤N≤1000
对于所有的数据 K≤N≤100000
所有的坐标绝对值小于10^6

题解:
排序+枚举:
因为题目中出现的距离要精确到小数点后4位,所以我们可以先将我们处理出来的距离a[i]*10000,注意处理过程要开int64,C++则开long long。
然后我们将a[i]排序,记得排序的时候相等时按输入顺序跟着排,然后处理K-1个人拿到的礼物,设前i-1个礼物是K-1个人的,则a[i]是给K的(a已排序),然后将连续的一段[i,j]输出对应的名字。
其中[i,j]这一段内所有的a[]都相等。
时间复杂度:O(NT)
T介于1~名字的最长长度之间

var
   a:array [0..100001] of int64;
   ans,b:array [0..100001] of longint;
   c:array [0..100001] of ansistring;
   i,j,n,m:longint;
   p,q,s:ansistring;
   x,y:int64;

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

begin
   readln(n,m);
   for i:=1 to n do
     begin
          readln(s);
          j:=pos(' ',s); c[i]:=copy(s,1,j-1);

          delete(s,1,j); j:=pos(' ',s);
          p:=copy(s,1,j-1); val(p,x);
          q:=copy(s,j+1,length(s)-j); val(q,y);
          a[i]:=trunc(sqrt(sqr(x)+sqr(y))*10000);
          b[i]:=i;
     end;
   qsort(1,n);
   i:=1; j:=0;
   while i<=n do
   begin
        inc(j);
        if j=m then
           begin
                ans[0]:=1;
                ans[1]:=b[i];
                while a[i]=a[i+1] do
                begin
                     inc(i);
                     inc(ans[0]);
                     ans[ans[0]]:=b[i];
                end;
                writeln(a[i] div 10000,' ',ans[0]);
                for j:=1 to ans[0] do writeln(c[ans[j]]);
                halt;
           end
        else while a[i]=a[i+1] do inc(i);
        inc(i);
   end;
   writeln('555');
end.
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值