题目链接:
题目大致意思:
指南针直接指向晨星。它只能指向八个方向中的一个:四个基本方向(N,S,E,W)或其中一些组合(NW,NE,SW,SE)。否则,它会坏掉。
指南针可以指向的方向。
平面上有n个不同的整数坐标点。有多少种方法可以把指南针放在一个点上,晨星放在另一个点上,以便指南针不会坏掉?
输入:
每个测试包含多个测试用例。第一行包含测试用例数量t(1≤t≤104)。接下来是测试用例的描述。
每个测试用例的第一行包含一个整数n(2≤n≤2⋅105)——点的数量。
然后是n行,每行包含两个整数xi,yi(−109≤xi,yi≤109)——每个点的坐标,所有点都有不同的坐标。
保证所有测试用例中n的总和不超过2⋅105。
输出:
对于每个测试用例,输出一个整数——不会破坏指南针的点对数量。
思路:
设立一个坐标系,8个方向可以理解为4条线(北方向和南方向是一条直线),一条直线的方程式是:y=nx+m,由于我们已经知道4条直线的n(角度是固定的),x,y,现在只需要知道m即可确定点在线上的位置,所以我们计算出m,然后用map标记m为下标的线,点的个数(ma[m]++),然后遍历map,计算出数量。
南,北方向:m=x(垂直于x轴)
东,西方向:m=y(垂直于y轴)
东北,西南方向:y=x-m ----> m=x-y
东南,西北方向:y=-x+m ----> m=x+y
代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll n,xi,yi,ans;
map<int,int>x;//垂直于x轴,m=x
map<int,int>y;//垂直于y轴,m=y
map<int,int>up;//向上的斜边,y=x-m -> m=x-y
map<int,int>down;//向下的斜边,y=-x+m -> m=x+y
int main(){
std::ios::sync_with_stdio(false);
cin.tie(0);
int t;
cin>>t;
while(t--){
ans=0;
x.clear();
y.clear();
up.clear();
down.clear();
cin>>n;
for(int i=0;i<n;i++){
cin>>xi>>yi;
x[xi]++;
y[yi]++;
up[xi-yi]++;
down[xi+yi]++;
}
for(auto it=x.begin();it!=x.end();it++){
ll cnt=it->second;
ans+=cnt*(cnt-1);
}
for(auto it=y.begin();it!=y.end();it++){
ll cnt=it->second;
ans+=cnt*(cnt-1);
}
for(auto it=up.begin();it!=up.end();it++){
ll cnt=it->second;
ans+=cnt*(cnt-1);
}
for(auto it=down.begin();it!=down.end();it++){
ll cnt=it->second;
ans+=cnt*(cnt-1);
}
cout<<ans<<"\n";
}
}