题目链接: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;
}