“玲珑杯”ACM比赛 Round #18 A -- 计算几何你瞎暴力

题目链接:http://www.ifrog.cc/acm/problem/1143

题目大意:n间教室,q次询问。每次询问是有多少对教室之间的距离不超过R。

教室之间的距离为:从一个坐标为 (x1,y1,z1)的教室走到(x2,y2,z2)的距离为 |x1−x2|+|y1−y2|+|z1−z2|。

分析:因为教室的坐标范围是0~10,对于5*10^4个教室我们可以先预处理一下,用三维数组统计其出现的次数和用结构体存不相同的点。然后两层循环遍历求出任意两点之间的距离,用数组存下来。再用一个前缀和数组预处理0~30出现的次数。询问的时候直接查询就可以了。不然的话可能会超时。也可以不用存点,直接6层10的for循环遍历所有的点,统计。

当时做比赛的时候把R>30的直接用n*(n-1)/2表示出来,一直WA,很郁闷。。。后来直接改成query[30]就过了,很坑啊!任意两点之间的距离一定在30以内,即任意两点都可以,感觉没什么问题啊,求dalao指点。

CODE:

#include<stdio.h>
#include<algorithm>
#include<string.h>
#include<vector>
#include<queue>
#include<math.h>
#include<stdlib.h>
#include<iostream>
#define INF 0x3f3f3f3f
typedef long long LL;
using namespace std;
const int maxn=1000008;
LL num[15][15][15];
LL sum[maxn];//统计距离为i的出现多少次
struct node
{
    int x,y,z;
} c[maxn],d[maxn];
bool cmp(node aa,node bb)
{
    if(aa.x==bb.x&&aa.y==bb.y)
        return aa.z<bb.z;
    else if(aa.x==bb.x)
        return aa.y<bb.y;
    else
        return aa.x<bb.x;
}
int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        int n,q;
        memset(num,0,sizeof(num));
        memset(d,0,sizeof(d));
        scanf("%d%d",&n,&q);
        for(int i=0; i<n; i++)
        {
            scanf("%d%d%d",&c[i].x,&c[i].y,&c[i].z);
            num[c[i].x][c[i].y][c[i].z]++;
        }
        int k=0;
        sort(c,c+n,cmp);
        d[k].x=c[0].x,d[k].y=c[0].y;
        d[k++].z=c[0].z;
        for(int i=1; i<n; i++)
        {
            if(c[i].x==c[i-1].x&&c[i].y==c[i-1].y&&c[i].z==c[i-1].z)
                continue;
            else
            {
                d[k].x=c[i].x,d[k].y=c[i].y;
                d[k++].z=c[i].z;
            }
        }
        memset(sum,0,sizeof(sum));
        LL ans0=0;
        for(int i=0; i<k; i++)
        {
            // cout<<d[i].x<<" "<<d[i].y<<" "<<d[i].z<<endl;
            // int kkk=num[d[i].x][d[i].y][d[i].z]-1;
            //printf("%d***\n",kkk);
            ans0+=(num[d[i].x][d[i].y][d[i].z])*(num[d[i].x][d[i].y][d[i].z]-1)/2;
            for(int j=i+1; j<k; j++)
            {
                int ans=abs(d[i].x-d[j].x)+abs(d[i].y-d[j].y)+abs(d[i].z-d[j].z);
                sum[ans]+=(num[d[i].x][d[i].y][d[i].z])*(num[d[j].x][d[j].y][d[j].z]);
            }
        }
        sum[0]=ans0;
        LL query[38];//前缀和
        memset(query,0,sizeof(query));
        query[0]=sum[0];
        for(int i=1;i<=30;i++)
            query[i]+=query[i-1]+sum[i];
        for(int i=0; i<q; i++)
        {
            int r;
            scanf("%d",&r);
            if(r>30)
                printf("%lld\n",query[30]);
            else
                printf("%lld\n",query[r]);
        }
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值