題意:平面內給定n個點,q次詢問,給次給定一個點P,問這個點與平面內n個點可以組成多少直角三角形,其中(n+q)個點互不相等
思路:
分別考慮P點作直角頂點和非直角頂點。這個題思路很簡單,就是看如何實現簡單而且不會tle!!!
對於直角頂點和非直角頂點代碼都比較簡單,求后者有點離線的思想。
這里想說的就是map的用法,自定義小於運算符,使得在map中查找的時候,統一斜率的向量都會加起來,雖然在map中依然會保存多個不同的向量。(聽說是現場一血的寫法,中山大學大佬nb)
算法復雜度大概n*n*log(n)(由於n和p的范圍一樣,這里統一同n表示),運行時間10s左右
代碼:
#include<bits/stdc++.h> using namespace std; #define ll long long const int N = 2005; struct P { ll x, 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); } }a[N],qur[N]; int n, q; map<P, int>m; ll ans[N]; int main() { while (~scanf("%d%d", &n, &q)) { memset(ans,0,sizeof(ans)); for (int i = 0; i < n; i++)scanf("%lld%lld", &a[i].x, &a[i].y); for (int i = 0; i < q; i++)scanf("%lld%lld", &qur[i].x, &qur[i].y); for (int i = 0; i < q; i++) { //求解作為直角頂點 m.clear(); for (int j = 0; j < n; j++) m[a[j] - qur[i]]++; for (int j = 0; j < n; j++) { P p = a[j] - qur[i]; p = P(-p.y, p.x); ans[i] += m.count(p) ? m[p] : 0; } //由於兩條直角邊都會枚舉,所以除2 ans[i] /= 2; } for (int i = 0; i < n; i++) { //作為非直角頂點,每次枚舉點i,作為直角頂點,更新全部的q組詢問點 m.clear(); for (int j = 0; j < n; j++) { if (i != j)m[a[j] - a[i]]++; } for (int j = 0; j < q; j++) { P p = qur[j] - a[i]; p = P(-p.y, p.x); ans[j] += m.count(p) ? m[p] : 0; } } for (int i = 0; i < q; i++)printf("%lld\n", ans[i]); } return 0; }