QOJ.ac

QOJ

ID题目提交者结果用时内存语言文件大小提交时间测评时间
#424613#1940. Shy Polygonscrimson231100 ✓39ms4016kbC++1713.7kb2024-05-29 14:17:272024-05-29 14:17:28

Judging History

你现在查看的是最新测评结果

  • [2024-05-29 14:17:28]
  • 评测
  • 测评结果:100
  • 用时:39ms
  • 内存:4016kb
  • [2024-05-29 14:17:27]
  • 提交

answer

#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <cassert>
#include <vector>
typedef long long ll;
//typedef long double ld;
typedef double ld;
const ld INF = 1e17;
const ld TOL = 1e-7;
const ld PI = acos(-1);
const int LEN = 1e3;
int N, M, T, Q;
bool zero(const ld& x) { return std::abs(x) < TOL; }
int sign(const ld& x) { return x < -TOL ? -1 : x > TOL; }
ll gcd(ll a, ll b) { return !b ? a : gcd(b, a % b); }

struct Pos {
	ld x, y;
	Pos(ld X = 0, ld Y = 0) : x(X), y(Y) {}
	bool operator == (const Pos& p) const { return zero(x - p.x) && zero(y - p.y); }
	bool operator != (const Pos& p) const { return !zero(x - p.x) || !zero(y - p.y); }
	bool operator < (const Pos& p) const { return zero(x - p.x) ? y < p.y : x < p.x; }
	bool operator <= (const Pos& p) const { return *this < p || *this == p; }
	Pos operator + (const Pos& p) const { return { x + p.x, y + p.y }; }
	Pos operator - (const Pos& p) const { return { x - p.x, y - p.y }; }
	Pos operator * (const ld& scalar) const { return { x * scalar, y * scalar }; }
	Pos operator / (const ld& scalar) const { return { x / scalar, y / scalar }; }
	ld operator * (const Pos& p) const { return x * p.x + y * p.y; }
	ld operator / (const Pos& p) const { return x * p.y - y * p.x; }
	Pos operator ^ (const Pos& p) const { return { x * p.x, y * p.y }; }
	Pos& operator += (const Pos& p) { x += p.x; y += p.y; return *this; }
	Pos& operator -= (const Pos& p) { x -= p.x; y -= p.y; return *this; }
	Pos& operator *= (const ld& scale) { x *= scale; y *= scale; return *this; }
	Pos& operator /= (const ld& scale) { x /= scale; y /= scale; return *this; }
	Pos operator - () const { return { -x, -y }; }
	Pos operator ~ () const { return { -y, x }; }
	Pos operator ! () const { return { y, x }; }
	ld xy() const { return x * y; }
	Pos rot(ld the) { return { x * cos(the) - y * sin(the), x * sin(the) + y * cos(the) }; }
	ld Euc() const { return x * x + y * y; }
	ld mag() const { return sqrt(Euc()); }
	Pos unit() const { return *this / mag(); }
	ld rad() const { return atan2(y, x); }
	friend ld rad(const Pos& p1, const Pos& p2) { return atan2l(p1 / p2, p1 * p2); }
	int quad() const { return sign(y) == 1 || (sign(y) == 0 && sign(x) >= 0); }
	friend bool cmpq(const Pos& a, const Pos& b) { return (a.quad() != b.quad()) ? a.quad() < b.quad() : a / b > 0; }
	bool close(const Pos& p) const { return zero((*this - p).Euc()); }
	friend std::istream& operator >> (std::istream& is, Pos& p) { is >> p.x >> p.y; return is; }
	friend std::ostream& operator << (std::ostream& os, const Pos& p) { os << p.x << " " << p.y; return os; }
}; const Pos O = { 0, 0 };
typedef std::vector<Pos> Polygon;
struct Vec {
	ld vy, vx;
	Vec(ld Y = 0, ld X = 0) : vy(Y), vx(X) {}
	bool operator == (const Vec& v) const { return (zero(vy - v.vy) && zero(vx - v.vx)); }
	bool operator < (const Vec& v) const { return zero(vy - v.vy) ? vx < v.vx : vy < v.vy; }
	ld operator * (const Vec& v) const { return vy * v.vy + vx * v.vx; }
	ld operator / (const Vec& v) const { return vy * v.vx - vx * v.vy; }
	Vec operator ~ () const { return { -vx, vy }; }
	Vec& operator *= (const ld& scalar) { vy *= scalar; vx *= scalar; return *this; }
	Vec& operator /= (const ld& scalar) { vy /= scalar; vx /= scalar; return *this; }
	ld mag() const { return hypot(vy, vx); }
}; const Vec Zero = { 0, 0 };
struct Line {//ax + by = c
	Vec s;
	ld c;
	Line(Vec V = Vec(0, 0), ld C = 0) : s(V), c(C) {}
	bool operator < (const Line& l) const {
		bool f1 = Zero < s;
		bool f2 = Zero < l.s;
		if (f1 != f2) return f1;
		ld CCW = s / l.s;
		return zero(CCW) ? c * hypot(l.s.vy, l.s.vx) < l.c * hypot(s.vy, s.vx) : CCW > 0;
	}
	ld operator * (const Line& l) const { return s * l.s; }
	ld operator / (const Line& l) const { return s / l.s; }
	Line operator + (const ld& scalar) const { return Line(s, c + hypot(s.vy, s.vx) * scalar); }
	Line operator - (const ld& scalar) const { return Line(s, c - hypot(s.vy, s.vx) * scalar); }
	Line operator * (const ld& scalar) const { return Line({ s.vy * scalar, s.vx * scalar }, c * scalar); }
	Line& operator += (const ld& scalar) { c += hypot(s.vy, s.vx) * scalar; return *this; }
	Line& operator -= (const ld& scalar) { c -= hypot(s.vy, s.vx) * scalar; return *this; }
	Line& operator *= (const ld& scalar) { s *= scalar, c *= scalar; return *this; }
	ld dist(const Pos& p) const { return s.vy * p.x + s.vx * p.y; }
	ld above(const Pos& p) const { return s.vy * p.x + s.vx * p.y - c; }
	ld mag() const { return s.mag(); }
	friend std::ostream& operator << (std::ostream& os, const Line& l) { os << l.s.vy << " " << l.s.vx << " " << l.c; return os; }
};
struct Linear {//ps[0] -> ps[1] :: refer to bulijiojiodibuliduo
	Pos ps[2];
	Pos dir_;
	Pos& operator[](int i) { return ps[i]; }
	Pos dir() const { return dir_; }
	Linear(Pos a = Pos(0, 0), Pos b = Pos(0, 0)) {
		ps[0] = a;
		ps[1] = b;
		dir_ = (ps[1] - ps[0]).unit();
	}
	bool include(const Pos& p) const { return sign(dir_ / (p - ps[0])) > 0; }
	Linear push() const {//push eps outward
		const double eps = 1e-8;
		Pos delta = ~(ps[1] - ps[0]).unit() * eps;
		return Linear(ps[0] + delta, ps[1] + delta);
	}
	Linear operator + (const double eps) const {//push eps outward
		Pos delta = ~(ps[1] - ps[0]).unit() * eps;
		return Linear(ps[0] + delta, ps[1] + delta);
	}
	Linear operator - (const double eps) const {//pull eps inward
		Pos delta = ~(ps[1] - ps[0]).unit() * eps;
		return Linear(ps[0] - delta, ps[1] - delta);
	}
	friend bool parallel(const Linear& l0, const Linear& l1) { return zero(l0.dir() / l1.dir()); }
	friend bool same_dir(const Linear& l0, const Linear& l1) { return parallel(l0, l1) && l0.dir() * l1.dir() > 0; }
	bool operator < (const Linear& l0) const {
		if (same_dir(*this, l0)) return l0.include(ps[0]);
		else return cmpq(this->dir(), l0.dir());
	}
};
const Line Xaxis = { { 0, -1 }, 0 };
const Line Yaxis = { { 1, 0 }, 0 };
Line L(const Pos& s, const Pos& e) {
	ld dy, dx, c;
	dy = e.y - s.y;
	dx = s.x - e.x;
	c = dy * s.x + dx * s.y;
	return Line(Vec(dy, dx), c);
}
Line L(const Vec& s, const Pos& p) {
	ld c = s.vy * p.x + s.vx * p.y;
	return Line(s, c);
}
Line rotate(const Line& l, const Pos& p, ld the) {
	Vec s = l.s;
	ld x = -s.vx, y = s.vy;
	ld vx = -(x * cos(the) - y * sin(the));
	ld vy = x * sin(the) + y * cos(the);
	ld c = vy * p.x + vx * p.y;
	return Line(Vec(vy, vx), c);
}
Line rotate90(const Line& l, const Pos& p) {
	Vec s = ~l.s;
	ld c = s.vy * p.x + s.vx * p.y;
	return Line(s, c);
}
Pos intersection(const Line& l1, const Line& l2) {
	Vec v1 = l1.s, v2 = l2.s;
	ld det = v1 / v2;
	return {
		(l1.c * v2.vx - l2.c * v1.vx) / det,
		(l2.c * v1.vy - l1.c * v2.vy) / det,
	};
}
ld rad(const Line& b, const Line& l) {
	ld x = (b * l) / b.mag();//dot
	ld y = (b / l) / b.mag();//cross
	return atan2(y, x);
}
ld cross(const Pos& d1, const Pos& d2, const Pos& d3) { return (d2 - d1) / (d3 - d2); }
ld cross(const Pos& d1, const Pos& d2, const Pos& d3, const Pos& d4) { return (d2 - d1) / (d4 - d3); }
int ccw(const Pos& d1, const Pos& d2, const Pos& d3) {
	ld ret = cross(d1, d2, d3);
	return zero(ret) ? 0 : ret > 0 ? 1 : -1;
}
ld dot(const Pos& d1, const Pos& d2, const Pos& d3) { return (d2 - d1) * (d3 - d2); }
ld dot(const Pos& d1, const Pos& d2, const Pos& d3, const Pos& d4) { return (d2 - d1) * (d4 - d3); }
bool on_seg_strong(const Pos& d1, const Pos& d2, const Pos& d3) {
	ld ret = dot(d1, d3, d2);
	return !ccw(d1, d2, d3) && (ret > 0 || zero(ret));
}
bool on_seg_weak(const Pos& d1, const Pos& d2, const Pos& d3) {
	ld ret = dot(d1, d3, d2);
	return !ccw(d1, d2, d3) && ret > 0;
}
inline bool collinear(const Pos& d1, const Pos& d2, const Pos& d3, const Pos& d4) {
	return !ccw(d1, d2, d3) && !ccw(d1, d2, d4);
}
ld projection(const Pos& d1, const Pos& d2, const Pos& d3, const Pos& d4) {
	return (d2 - d1) * (d4 - d3) / (d2 - d1).mag();
}
ld dist(const Pos& d1, const Pos& d2, const Pos& t, bool f = 0) {
	if (f) return std::abs(cross(d1, d2, t)) / (d1 - d2).mag();
	if (sign(projection(d1, d2, d2, t)) <= 0 &&
		sign(projection(d2, d1, d1, t)) <= 0)
		return std::abs(cross(d1, d2, t)) / (d1 - d2).mag();
	return std::min((d1 - t).mag(), (d2 - t).mag());
}
Pos intersection(const Pos& p1, const Pos& p2, const Pos& q1, const Pos& q2) {
	ld a1 = cross(q1, q2, p1), a2 = -cross(q1, q2, p2);
	return (p1 * a2 + p2 * a1) / (a1 + a2);
}
Pos intersection(Linear& l1, Linear& l2) { return intersection(l1[0], l1[1], l2[0], l2[1]); }
bool intersect(const Pos& s1, const Pos& s2, const Pos& d1, const Pos& d2) {
	bool f1 = ccw(s1, s2, d1) * ccw(s2, s1, d2) > 0;
	bool f2 = ccw(d1, d2, s1) * ccw(d2, d1, s2) > 0;
	//return f1 && f2;
	bool f3 = on_seg_strong(s1, s2, d1) ||
		on_seg_strong(s1, s2, d2) ||
		on_seg_strong(d1, d2, s1) ||
		on_seg_strong(d1, d2, s2);
	return (f1 && f2) || f3;
}
bool inner_check(const std::vector<Pos>& H, const Pos& p) {//concave
	int cnt = 0, sz = H.size();
	for (int i = 0; i < sz; i++) {
		Pos cur = H[i], nxt = H[(i + 1) % sz];
		if (on_seg_strong(cur, nxt, p)) return 1;
		if (zero(cur.y - nxt.y)) continue;
		if (nxt.y < cur.y) std::swap(cur, nxt);
		if (nxt.y - TOL < p.y || cur.y > p.y) continue;
		cnt += ccw(cur, nxt, p) > 0;
	}
	return cnt & 1;
}
ld area(std::vector<Pos>& H) {
	Pos pivot = Pos(0, 0);
	ld ret = 0;
	int h = H.size();
	for (int i = 0; i < h; i++) {
		Pos cur = H[i], nxt = H[(i + 1) % h];
		ret += cross(pivot, cur, nxt);
	}
	return ret / 2;
}
void norm(std::vector<Pos>& H) { if (area(H) < 0) std::reverse(H.begin(), H.end()); }
bool valid_check(const Polygon& A, const Polygon& B, const ld& D) {
	int sza = A.size(), szb = B.size();
	for (int i = 0; i < sza; i++) {
		for (int j = 0; j < szb; j++) {
			int ii = (i + 1) % sza;
			int jj = (j + 1) % szb;
			if (intersect(A[i], A[ii], B[j], B[jj])) return 0;
			if (sign(D - dist(A[i], A[ii], B[j])) > 0) return 0;
			if (sign(D - dist(A[i], A[ii], B[jj])) > 0) return 0;
			if (sign(D - dist(B[j], B[jj], A[i])) > 0) return 0;
			if (sign(D - dist(B[j], B[jj], A[ii])) > 0) return 0;
		}
	}
	return !inner_check(A, B[0]) && !inner_check(B, A[0]);
}
std::vector<Pos> circle_line_intersection(const Pos& o, const ld& r, const Pos& p1, const Pos& p2) {
	ld d = dist(p1, p2, o, 1);
	if (std::abs(d) > r) return {};
	Pos vec = p2 - p1;
	Pos m = intersection(p1, p2, o, o + ~vec);
	ld distance = vec.mag();
	ld ratio = sqrt(r * r - d * d);
	Pos m1 = m - vec * ratio / distance;
	Pos m2 = m + vec * ratio / distance;
	if (dot(p1, p2, m1, m2) < 0) std::swap(m1, m2);
	return { m1, m2 };//p1->p2
}
std::vector<ld> dists(const Pos& a1, const Pos& a2, const Pos& b, const ld& D) {
	std::vector<ld> ret;
	std::vector<Pos> tmp;
	Pos v = ~(a1 - a2).unit();
	Pos p1 = a1 + v * D, p2 = a2 + v * D;
	Pos q1 = a1 - v * D, q2 = a2 - v * D;
	Pos b1 = b + Pos(1, 0);
	if (ccw(b, b1, p1) * ccw(b, b1, p2) <= 0) tmp.push_back(intersection(b, b1, p1, p2));
	if (ccw(b, b1, q1) * ccw(b, b1, q2) <= 0) tmp.push_back(intersection(b, b1, q1, q2));
	auto inx1 = circle_line_intersection(a1, D, b, b1);
	for (const Pos& p : inx1) tmp.push_back(p);
	auto inx2 = circle_line_intersection(a2, D, b, b1);
	for (const Pos& p : inx2) tmp.push_back(p);
	for (const Pos& p : tmp) {
		ld d = dist(a1, a2, p);
		if (sign(D - d) >= 0) ret.push_back((b - p).mag() * sign(dot(b, b1, p)));
	}
	return ret;
}
ld max(const Polygon& A, const Polygon& B) {
	ld maxx = -INF, minx = INF;
	for (const Pos& p : A) {
		maxx = std::max(maxx, p.x);
		minx = std::min(minx, p.x);
	}
	for (const Pos& p : B) {
		maxx = std::max(maxx, p.x);
		minx = std::min(minx, p.x);
	}
	return maxx - minx;
}
bool query() {
	ld D;
	ld maxx = -INF, minx = INF;
	ld amaxx = -INF, aminx = INF;
	ld bmaxx = -INF, bminx = INF;

	std::cin >> D;
	if (zero(D)) return 0;
	std::cin >> N;
	Polygon A(N);
	for (Pos& p : A) {
		std::cin >> p;
		maxx = std::max(maxx, p.x);
		minx = std::min(minx, p.x);
		amaxx = std::max(amaxx, p.x);
		aminx = std::min(aminx, p.x);
	}
	norm(A);
	std::cin >> M;
	Polygon B(M);
	for (Pos& p : B) {
		std::cin >> p;
		maxx = std::max(maxx, p.x);
		minx = std::min(minx, p.x);
		bmaxx = std::max(bmaxx, p.x);
		bminx = std::min(bminx, p.x);
	}
	norm(B);

	//brute
	ld ans = INF;
	bool F = 0;
	if (valid_check(A, B, D)) ans = std::min(ans, maxx - minx);
	for (int i = 0; i < N; i++) {
		for (int j = 0; j < M; j++) {
			int ii = (i + 1) % N;
			auto VD = dists(A[i], A[ii], B[j], D);
			//std::cout << "DEBUG:: VD " << VD.size() << " DEBUG::\n";
			for (const ld& d : VD) {
				F = 1;
				Polygon MB;
				for (const Pos& p : B) MB.push_back(p + Pos(1, 0) * d);
				if (valid_check(MB, A, D)) {
					ld MIN = std::min(aminx, bminx + d);
					ld MAX = std::max(amaxx, bmaxx + d);
					ans = std::min(ans, MAX - MIN);
					//ans = std::min(ans, max(MB, A));
				}
			}
			int jj = (j + 1) % M;
			auto WD = dists(B[j], B[jj], A[i], D);
			//std::cout << "DEBUG:: WD" << WD.size() << " DEBUG::\n";
			for (const ld& d : WD) {
				F = 1;
				Polygon MA;
				for (const Pos& p : A) MA.push_back(p + Pos(1, 0) * d);
				if (valid_check(MA, B, D)) {
					ld MIN = std::min(aminx + d, bminx);
					ld MAX = std::max(amaxx + d, bmaxx);
					ans = std::min(ans, MAX - MIN);
					//ans = std::min(ans, max(MA, B));
				}
			}
		}
	}
	if (!F) ans = std::min(amaxx - aminx, bmaxx - bminx);
	std::cout << ans << "\n";
	return 1;
}
void solve() {
	std::cin.tie(0)->sync_with_stdio(0);
	std::cout.tie(0);
	std::cout << std::fixed;
	std::cout.precision(5);
	//freopen("shy_in.txt", "r", stdin);
	//freopen("shy_out.txt", "w", stdout);
	while (query()) {}
	return;
}
int main() { solve(); return 0; }//boj3922 Shy Polygon

/*

10.5235
3
0 0
100 100
0 100
4
0 50
20 50
20 80
0 80
0

114.882476

*/

詳細信息

Test #1:

score: 100
Accepted
time: 39ms
memory: 4016kb

input:

2.1
9
0 70
10 45
21 70
33 45
46 70
60 45
75 70
75 100
0 100
9
0 0
75 0
75 55
65 30
54 55
42 30
29 55
15 30
0 55
4.1
9
0 70
10 45
21 70
33 45
46 70
60 45
75 70
75 100
0 100
9
0 0
75 0
75 55
65 30
54 55
42 30
29 55
15 30
0 55
5.1
9
0 70
10 45
21 70
33 45
46 70
60 45
75 70
75 100
0 100
9
0 0
75 0
75 55...

output:

78.56695
93.87933
118.94831
149.27995
110.50050
1.00000
100.00000
399.30000
404.24350
409.12432
419.23134
439.11111
501.30000
506.24350
511.12432
521.23134
541.11111
401.30000
406.24350
411.12432
421.23134
441.11111
200.83848
207.82964
214.73216
229.02565
254.91829
300.30000
305.24350
310.12432
320....

result:

ok 412 numbers