Contest Hunter Round #46 磁力块

描述

在一片广袤无垠的原野上,散落着N块磁石。每个磁石的性质可以用一个五元组(x,y,m,p,r)描述,其中x,y表示其坐标,m是磁石的质量,p是磁力,r是吸引半径。若磁石A与磁石B的距离不大于磁石A的吸引半径,并且磁石B的质量不大于磁石A的磁力,那么A可以吸引B。
小取酒带着一块自己的磁石L来到了这篇原野的(x0,y0)处,我们可以视为磁石L的坐标为(x0,y0)。小取酒手持磁石L并保持原地不动,所有可以被L吸引的磁石将会被吸引过来。在每个时刻,他可以选择更换任意一块自己已经获得的磁石(当然也可以是自己最初携带的L磁石)在(x0,y0)处吸引更多的磁石。小取酒想知道,他最多能获得多少块磁石呢?
输入格式

第一行五个整数x0,y0,pL,rL,N,表示小取酒所在的位置,磁石L磁力、吸引半径和原野上散落磁石的个数。
接下来N行每行五个整数x,y,m,p,r,描述一块磁石的性质。 输出格式

输出一个整数,表示最多可以获得的散落磁石个数(不包含最初携带的磁石L)。

把所有石头按照质量排序分成sqrt(n)块,每一块里面再按照距离排序。
用一块石头的时候,先找到所有质量全小于当前磁力的整块,然后按顺序拿走距离满足要求的,多出来的那一块暴力。
整个操作可以分成两部分,取整块的和取不完整的。对于整块的,寻找需要O(sqrt(n))次,总共寻找O(n)次。每块只会被取一次,总共O(n)次。多出来的一段,每次暴力O(sqrt(n))个,暴力O(n)次。所以总的复杂度O(n*sqrt(n))。

#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#define LL long long
using namespace std;
const double eps=1e-6;
struct rock
{
    int m,p,r;
    double d;
}a[250010];
int rd()
{
    int x=0,f=1;
    char c=getchar();
    while ((c<'0'||c>'9')&&c!='-') c=getchar();
    if (c=='-')
    {
        f=-1;
        c=getchar();
    }
    while (c>='0'&&c<='9')
    {
        x=x*10+c-'0';
        c=getchar();
    }
    return x*f;
}
bool cmpm(const rock &r1,const rock &r2)
{
    return r1.m<r2.m;
}
bool cmpd(const rock &r1,const rock &r2)
{
    return r1.d<r2.d;
}
bool out[250010];
int L[510],R[510],maxm[510],to[510],n,tot,que[250010];
int main()
{
    int i,j,k,m,n,p,q,x0,y0,hd,tl,ans=0;
    double x,y,z;
    x0=rd();
    y0=rd();
    a[0].p=rd();
    a[0].r=rd();
    n=rd();
    for (i=1;i<=n;i++)
    {
        p=rd();
        q=rd();
        a[i].m=rd();
        a[i].p=rd();
        a[i].r=rd();
        a[i].d=sqrt((LL)(p-x0)*(p-x0)+(LL)(q-y0)*(q-y0)+0.0);
    }
    sort(a+1,a+n+1,cmpm);
    tot=sqrt(n+0.1);
    for (i=1;i<=tot;i++)
    {
        L[i]=R[i-1]+1;
        to[i]=L[i]-1;
        R[i]= i==tot?n:L[i]+tot-1;
        maxm[i]=a[R[i]].m;
    }
    for (i=1;i<=tot;i++)
      sort(a+L[i],a+R[i]+1,cmpd);
    hd=tl=1;
    while (hd<=tl)
    {
        p=que[hd++];
        for (i=1;i<=tot&&maxm[i]<=a[p].p;i++)
        {
            while (to[i]<R[i]&&a[to[i]+1].d<=eps+a[p].r)
            {
                to[i]++;
                if (!out[to[i]])
                {
                    que[++tl]=to[i];
                    ans++;
                    out[to[i]]=1;
                }
            }
        }
        if (i<=tot)
          for (j=to[i]+1;j<=R[i];j++)
            if (out[j]==0&&a[j].d<=eps+a[p].r&&a[j].m<=a[p].p)
            {
                out[j]=1;
                ans++;
                que[++tl]=j;
            }
    }
    printf("%d\n",ans);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值