【CodeForces645G】Armistice Area Apportionment

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_39972971/article/details/89215945

【题目链接】

【思路要点】

  • 考虑找到使得 P X Q X |PX-QX| 最小的 X X X X 应为 P P 关于 l l 的对称点 P P' Q Q 所连直线与 l l 的交点,若两直线平行,则 X X 可取无穷远处的一点。
  • 此时 P X Q X = P Q |PX-QX|=P'Q ,因此原问题即为任取一条直线,找到 P P 的对称点距离 Q Q 的最短距离。
  • 考虑二分答案 m i d mid ,我们需要判断是否存在一条直线使得 P P 的对称点在 Q Q 为圆心, m i d mid 为半径的圆内,不妨设为圆 Q Q
  • 注意到 P P 关于直线 A B AB 的对称点 P P' 同时也可以看做 A A 为圆心, A P AP 为半径的圆和 B B 为圆心, B P BP 为半径的圆的另一个交点。
  • 由此,我们可以将 A A B B 分开考虑。
  • 记圆 Q Q A A 为圆心, A P AP 为半径的圆内的圆周为 A r c A Arc_A P P 关于直线 A B AB 的对称点 P P' 在圆 Q Q 内当且仅当 A r c A , A r c B Arc_A,Arc_B 均非空,且不存在包含关系。
  • 由此,我们只需要判断一些环上的区间是否存在相交关系即可,可以排序后用栈来判断。
  • 时间复杂度 O ( N L o g N L o g V ) O(NLogNLogV)

【代码】

#include<bits/stdc++.h>
using namespace std;
const int MAXN = 2e5 + 5;
const double eps = 1e-10;
typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;
template <typename T> void chkmax(T &x, T y) {x = max(x, y); }
template <typename T> void chkmin(T &x, T y) {x = min(x, y); } 
template <typename T> void read(T &x) {
	x = 0; int f = 1;
	char c = getchar();
	for (; !isdigit(c); c = getchar()) if (c == '-') f = -f;
	for (; isdigit(c); c = getchar()) x = x * 10 + c - '0';
	x *= f;
}
template <typename T> void write(T x) {
	if (x < 0) x = -x, putchar('-');
	if (x > 9) write(x / 10);
	putchar(x % 10 + '0');
}
template <typename T> void writeln(T x) {
	write(x);
	puts("");
}
struct point {double x, y; };
struct circle {point o; double r; };
point operator + (point a, point b) {return (point) {a.x + b.x, a.y + b.y}; }
point operator - (point a, point b) {return (point) {a.x - b.x, a.y - b.y}; }
point operator * (point a, double b) {return (point) {a.x * b, a.y * b}; }
double operator * (point a, point b) {return a.x * b.y - a.y * b.x; }
double moo(point a) {return sqrt(a.x * a.x + a.y * a.y); }
point unit(point a) {return a * (1.0 / moo(a)); }
double dist(point a, point b) {return moo(b - a); }
double PolarAngle(point a) {return atan2(a.y, a.x); }
pair <point, point> intersect(circle a, circle b) {
	double d = dist(a.o, b.o);
	double x = (a.r * a.r + d * d - b.r * b.r) / (2 * d);
	double z = sqrt(a.r * a.r - x * x);
	point u = unit(b.o - a.o);
	point mid = a.o + u * x;
	swap(u.x, u.y), u.x *= -1;
	return make_pair(mid + u * z, mid - u * z);
}
int n; double l;
circle a[MAXN];
point p, q;
bool valid(double mid) {
	circle o = (circle) {p, mid};
	vector <pair <double, int>> res;
	int tot = 0;
	for (int i = 1; i <= n; i++) {
		double d = dist(o.o, a[i].o);
		if (o.r + a[i].r > d && fabs(o.r - a[i].r) < d) {
			tot++;
			pair <point, point> tmp = intersect(o, a[i]);
			res.emplace_back(PolarAngle(tmp.first - o.o), tot);
			res.emplace_back(PolarAngle(tmp.second - o.o), tot);
		}
	}
	if (res.empty()) return false;
	sort(res.begin(), res.end());
	static int Stack[MAXN]; int top = 0;
	for (auto x : res) {
		if (Stack[top] == x.second) top--;
		else Stack[++top] = x.second;
	}
	return top != 0;
}
int main() {
	read(n), read(l);
	p = (point) {l, 0}, q = (point) {-l, 0};
	for (int i = 1; i <= n; i++) {
		read(a[i].o.x), read(a[i].o.y);
		a[i].r = dist(a[i].o, q);
	}
	double l = 0, r = dist(p, q);
	while (r - l >= eps) {
		double mid = (l + r) / 2;
		if (valid(mid)) r = mid;
		else l = mid;
	}
	printf("%.8lf\n", (l + r) / 2);
	return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_39972971/article/details/89215945