原题链接
题目来源:CCPC2019 秦皇岛站 A题
问题重述
给定二维平面上
n
n
n个点,然后给出q次询问,每次询问给出一个点P(n+q个点都不同),询问P和之前的n个点能构成多少个直角三角形。
其中
0
≤
n
,
q
≤
2000
;
∣
x
∣
,
∣
y
∣
≤
1
e
9
0 \leq n,q \leq 2000; |x|,|y|\leq 1e9
0≤n,q≤2000;∣x∣,∣y∣≤1e9
问题分析
假设存在两个点A,B跟这次的这个P构成了直角三角形, 那么可以得到以下的式子:
{
P
y
−
A
y
P
x
−
A
x
⋅
P
y
−
B
y
P
x
−
B
x
=
−
1
,
P
是
顶
点
A
y
−
P
y
A
x
−
P
x
⋅
A
y
−
B
y
A
x
−
B
x
=
−
1
,
P
不
是
顶
点
\begin{cases} {Py-Ay\over Px-Ax} \cdot {Py-By \over Px-Bx} = -1&,P是顶点\\ {Ay-Py\over Ax-Px} \cdot {Ay-By \over Ax-Bx} = -1&,P不是顶点 \end{cases}
{Px−AxPy−Ay⋅Px−BxPy−By=−1Ax−PxAy−Py⋅Ax−BxAy−By=−1,P是顶点,P不是顶点
然后我们发现这个复杂度可以支持
O
(
n
2
l
o
g
n
)
O(n^2logn)
O(n2logn)
分成两个部分来实现:
- P是直角顶点,预先处理好P和剩下的n个点的斜率ma。然后枚举一个点A,从ma里面查有没有斜率满足乘积为-1的,然后统计到答案就行了。不过这里要注意,A、B都在n个点之中,所以要统计完了之后除2。
- P不是直角顶点,那就枚举一个直角顶点,然后预先处理好和剩下的点的斜率。然后枚举q个询问点作为非直角顶点的一个点,然后查有没有满足斜率相乘为-1的点即可。这里不会算重复,所以放心统计就行了。
下面这个写挂了
- 如果P不是直角顶点,那我可以直接枚举另一个直角顶点A,然后在A里面查斜率满足乘积为-1的部分。需要预先处理好任意一个点A对其他点的斜率。预处理复杂度为
O
(
n
2
)
O(n^2)
O(n2)。不过实现的过程中
由于对map不熟导致预处理出来的数据不对。
为啥会WA
- 存斜率的时候不要直接就float了,由于斜率一定是整数,可以搞成点对的形式去存(也就是向量)。然后注意统一方向,比如下面的保证 ( x , y ) , x ≥ 0 并 且 x = 0 时 y ≥ 0 (x,y), x\geq 0 并且 x=0时y \geq 0 (x,y),x≥0并且x=0时y≥0
- 为啥这个题有多组数据?不是没有吗?
代码实现
#include<bits/stdc++.h>
using namespace std;
const int N = 2017;
int n, q;
struct Point{
long long x, y;
Point(int a,int b){
x = a; y = b;
}
Point(){
x = y = 0;
}
}p1[N], p2[N];
long long ans[N];
struct Vect{
long long dx, dy;
void trans(){
if(dx<0 or (dx==0 and dy<0)){
dx = -dx; dy = -dy;
}
}
Vect(Point a, Point b){
dx = a.x - b.x;
dy = a.y - b.y;
this->trans();
}
Vect(long long a, long long b){
dx = a; dy = b;
this->trans();
}
bool operator<(const Vect& a)const{
return dy * a.dx < dx * a.dy;
}
};
map<Vect, int>ma;
int main(){
while(~scanf("%d%d",&n,&q)){
//scanf("%d%d",&n,&q);
for(int i=1;i<=n;++i){
scanf("%lld%lld",&p1[i].x,&p1[i].y);
}
for(int i=1;i<=q;++i){
scanf("%lld%lld",&p2[i].x,&p2[i].y);
ans[i] = 0;
}
//Do if it is angle 90
for(int i=1;i<=q;++i){
ma.clear();
for(int j=1;j<=n;++j)
ma[Vect(p1[j], p2[i])]++;
for(int j=1;j<=n;++j){
Vect p = Vect(p1[j], p2[i]);
p = Vect(-p.dy, p.dx);
ans[i] += ma.count(p)? ma[p] : 0;
}
ans[i] /= 2;
}
//Do if it is not angle 90
for(int i=1;i<=n;++i){
ma.clear();
for(int j=1;j<=n;++j)
if(i!=j) ma[Vect(p1[i], p1[j])]++;
for(int j=1;j<=q;++j){
Vect p(p2[j], p1[i]);
p = Vect(-p.dy, p.dx);
ans[j] += ma.count(p)? ma[p]:0;
}
}
for(int i=1;i<=q;++i)
printf("%lld\n", ans[i]);
}
return 0;
}