传送门:QAQ
题意:给你n个点,然后有q次询问一个点,询问能和这n个点组成多少个直角三角形。
2≤n≤2000,1≤q≤2000
思路:首先回想到分类讨论,询问点作为直角点和不为直角点,然后就会想到存斜率,利用直角斜率的性质去计数。
果然第一发map+pair tle了,常数太大,外加自己处理太粗糙。
上网查题解时,发现存在两种做法,一种就是用unorder_map或者自己hash斜率(其实这两种做法一样),还有一种做法就是用map重构小于号(从来没见过,真的奇妙)。实现的想法都一样,在于处理的方式。
实现第二种方法的时候还是出现了问题
https://pasteme.cn/21708 三份代码的时间
有时候为了省count的时间而多加数据增大log原来也会炸。
附上代码:
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<vector>
#include<map>
#include<cmath>
#include<algorithm>
using namespace std;
typedef long long ll;
struct P {
ll x;
ll y;
P(ll xx = 0, ll yy = 0) {
x = xx; y = yy;
}
P base()const {
if (x < 0 || (x == 0 && y < 0))return P(-x, -y);
return *this;
}
bool operator<(const P&b)const {
P p1 = base(); P p2 = b.base();
return p1.x*p2.y < p1.y*p2.x;
}
P operator-(const P&b)const {
return P(x - b.x, y - b.y);
}
};
P ax[2100];
ll ans[2100];
P bn[2100];
map<P, int>mhh;
int main(void) {
int n, q;
scanf("%d%d", &n, &q);
for (int i = 0; i < n; i++) {
scanf("%lld%lld", &ax[i].x, &ax[i].y);
}
memset(ans, 0, sizeof(ans));
for (int i = 0; i < q; i++) {
scanf("%lld%lld", &bn[i].x, &bn[i].y);
}
//printf("111\n");
int num1, num2;
for (int z = 0; z < q; z++) {
mhh.clear();
for (int i = 0; i < n; i++) {
mhh[ax[i]-bn[z]]++;
//printf("-------------%d %d %d\n", i, num1, num2);
}
for (int i = 0; i < n; i++) {
P p = ax[i]-bn[z];
p = P(-p.y, p.x);
ans[z] += mhh.count(p) ? mhh[p] : 0;
}
ans[z] = ans[z] / 2;
}
for (int i = 0; i < n; i++) {
mhh.clear();
for (int z = 0; z < n; z++) {
if (i == z) continue;
mhh[ax[z]-ax[i]]++;
//printf("****%d %d %d\n", i,num1, num2);
}
for (int z = 0; z < q; z++) {
P p = bn[z] - ax[i];
p = P(-p.y, p.x);
ans[z] += mhh.count(p) ? mhh[p] : 0;
}
}
for (int i = 0; i < q; i++) {
printf("%lld\n", ans[i]);
}
}