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;
}
posted @ 2018-08-13 11:07  King_George  阅读(344)  评论(0编辑  收藏  举报