题目连接
题意
- 就是给你 n ( n ≤ 2000 ) n(n\leq 2000) n(n≤2000)个整数点, q ( q ≤ 2000 ) q(q\leq 2000) q(q≤2000)个询问,每次询问给你一个点 p ( x , y ) p(x,y) p(x,y),求 n n n个点中有多少点对 ( u , v ) (u,v) (u,v),使得 u , v , p u,v,p u,v,p三点构成直角三角形,保证所有 n + q n+q n+q个点两两互不相同
题解
-
两种解法:第一种哈希,第二种二分
-
分两种情况讨论一下
- 点 p p p作为直角
- 点 p p p作为直角三角形当中的一个锐角
首先需要预处理出所有 n n n个点两两之间的斜率,要么把用分数表示斜率的分子和分母 h a s h hash hash,成一个数,要么用一个表示分数的结构体表示即可,然后对于第一种情况,每次询问先预处理出 p p p与所有 n n n个点之间的斜率,然后用 h a s h hash hash或者二分(重载一下结构体即可)去查询与他垂直的点数量,这样一个直角三角形被统计了两次,答案除以 2 2 2,对于第二种类似处理即可,注意哈希方法过不了 h d u o j hduoj hduoj,卡了内存,现场赛是给了两个 G G G的
复杂度
- 二分 ( O ( q × n × log n ) ) (O(q\times n\times \log n)) (O(q×n×logn))
- 哈希 ( O ( q × n × log n ) ) (O(q\times n\times \log n)) (O(q×n×logn))
代码一(哈希)
#include<bits/stdc++.h>
using namespace std;
const int maxn=2e3+10;
struct point{
int x,y;
point(int a=0,int b=0) {x=a;y=b;}
point operator-(point other) {return point(x-other.x,y-other.y);}
}a[maxn];
int gcd(int a,int b) {return b==0?a:gcd(b,a%b);}
unordered_map<unsigned long long,int>o[maxn],b;
unsigned int Hash(point p) {
int GCD=gcd(abs(p.x),abs(p.y));
p.x/=GCD,p.y/=GCD;
if(p.x<0) {p.x=-p.x;p.y=-p.y;}
if(p.x==0) p.y=1;
return (unsigned int)p.x*233334*233334+(unsigned int)p.y*233333;
}
int n,q,x,y;
unsigned int k[maxn];
int main() {
while(~scanf("%d %d",&n,&q)) {
for(int i=1;i<=n;i++) scanf("%d %d",&a[i].x,&a[i].y);
for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) if(j!=i) o[i][Hash(a[j]-a[i])]++;
while(q--) {
long long ans=0;
scanf("%d %d",&x,&y);
for(int i=1;i<=n;i++) k[i]=Hash(point(a[i].y-y,-(a[i].x-x)));
for(int i=1;i<=n;i++) b[Hash(a[i]-point(x,y))]++;
for(int i=1;i<=n;i++) ans+=b[k[i]];
ans/=2;
for(int i=1;i<=n;i++) ans+=o[i][k[i]];
printf("%lld\n",ans);
b.clear();
}
for(int i=1;i<=n;i++) o[i].clear();
}
}
代码二(二分)
#include<bits/stdc++.h>
using namespace std;
const int maxn=2e3+10;
struct point{
int x,y;
point(int a=0,int b=0) {x=a;y=b;}
point operator-(point other) {return point(x-other.x,y-other.y);}
friend bool operator<(const point &a,const point &b) {
return 1LL*a.y*b.x<1LL*a.x*b.y;
}
friend void init(point &p) {
if(p.x<0) {p.x=-p.x,p.y=-p.y;}
if(p.x==0) p.y=1;
}
}a[maxn],b[maxn],o[maxn][maxn];
int n,x,y,q;
int main() {
while(~scanf("%d %d",&n,&q)) {
for(int i=1;i<=n;i++) scanf("%d %d",&a[i].x,&a[i].y);
for(int i=1;i<=n;i++) {
int qwq=0;
for(int j=1;j<=n;j++) if(j!=i) o[i][++qwq]=(a[j]-a[i]),init(o[i][qwq]);
}
for(int i=1;i<=n;i++) sort(o[i]+1,o[i]+n);
while(q--) {
scanf("%d %d",&x,&y);
for(int i=1;i<=n;i++) b[i]=a[i]-point(x,y),init(b[i]);
sort(b+1,b+n+1);long long ans=0;
for(int i=1;i<=n;i++) {
point chuizhi=point(b[i].y,-b[i].x);init(chuizhi);
ans+=upper_bound(b+1,b+n+1,chuizhi)-lower_bound(b+1,b+n+1,chuizhi);
}
ans/=2;
for(int i=1;i<=n;i++) {
point chuizhi=point(y-a[i].y,-(x-a[i].x));init(chuizhi);
ans+=upper_bound(o[i]+1,o[i]+n,chuizhi)-lower_bound(o[i]+1,o[i]+n,chuizhi);
}
printf("%lld\n",ans);
}
}
}