CF1019D
题意
给平面上 \(n\) 个无三点共线和重点的点。
问是否存在三个点构成面积为 \(S\) 的三角形。
\(3\ \leq\ n\ \leq\ 2000,\ 1\ \leq\ S\ \leq\ 2\ \cdot\ 10^{18},\ -10^9\ \leq\ x,\ y\ \leq\ 10^9\)
做法1
求出两两叉积然后暴力 \(O(n^3)\) 枚举,枚举的时候注意最内层用 register,并且前两层算出的值与S做差存在变量中常数就小了。
做法2
将两两连线产生的直线极角排序,依次考虑以每条边为底是否存在三角形。
如果能维护出其余点关于该斜率直线 \(kx\ +\ b\) 按 \(b\) 的顺序,则可以通过二分解决。
按极角顺序依次扫描,扫完两点连线的一条直线之后只用交换这两点的顺序,可以证明其余点之间的相对位置不变。
时间复杂度 \(O(n^2\ log\ n)\)
代码
#include <bits/stdc++.h>
#ifdef DEBUG
#define debug(...) fprintf(stderr, __VA_ARGS__)
#else
#define debug(...)
#endif
#ifdef __WIN32
#define LLFORMAT "I64"
#define Rand() ((rand() << 15) + rand())
#else
#define LLFORMAT "ll"
#define Rand() (rand())
#endif
using namespace std;
const int maxn = 2010;
struct point {
int x, y;
point() {}
point(int x, int y): x(x), y(y) {}
} a[maxn];
point operator - (const point &a, const point &b) { return point(a.x - b.x, a.y - b.y); }
long long det(const point &a, const point &b) { return (long long) a.y * b.x - (long long) a.x * b.y; }
int n, rnk[maxn], p[maxn];
long long S;
vector<pair<point, pair<int, int> > > b;
int main() {
scanf("%d%"LLFORMAT"d", &n, &S); S <<= 1;
for (int i = 1; i <= n; ++i) {
int x, y;
scanf("%d%d", &x, &y);
a[i] = point(x, y);
rnk[i] = p[i] = i;
}
sort(a + 1, a + n + 1, [&](point s, point t) {
return s.y == t.y ? s.x < t.x : s.y < t.y;
});
for (int i = 1; i <= n; ++i) for (int j = i + 1; j <= n; ++j) b.push_back(make_pair(a[j] - a[i], make_pair(i, j)));
sort(b.begin(), b.end(), [&](pair<point, pair<int, int> > a, pair<point, pair<int, int> > b) {
return det(a.first, b.first) < 0;
});
for (int k = 0; k < b.size(); ++k) {
int i = b[k].second.first, j = b[k].second.second, lb, rb;
lb = 1, rb = rnk[i] - 1;
while(lb <= rb) {
int mid = lb + rb >> 1, k = p[mid];
long long s = det(a[i], a[j]) + det(a[j], a[k]) + det(a[k], a[i]);
if(s < S) rb = mid - 1;
else if(s == S) { printf("Yes\n%d %d\n%d %d\n%d %d\n", a[i].x, a[i].y, a[j].x, a[j].y, a[k].x, a[k].y); return 0; }
else lb = mid + 1;
}
lb = rnk[i] + 1, rb = n;
while(lb <= rb) {
int mid = lb + rb >> 1, k = p[mid];
long long s = det(a[i], a[j]) + det(a[j], a[k]) + det(a[k], a[i]);
if(s < S) lb = mid + 1;
else if(s == S) { printf("Yes\n%d %d\n%d %d\n%d %d\n", a[i].x, a[i].y, a[j].x, a[j].y, a[k].x, a[k].y); return 0; }
else rb = mid - 1;
}
swap(p[rnk[i]], p[rnk[j]]);
swap(rnk[i], rnk[j]);
}
puts("No");
return 0;
}