QOJ.ac
QOJ
ID | Problem | Submitter | Result | Time | Memory | Language | File size | Submit time | Judge time |
---|---|---|---|---|---|---|---|---|---|
#424613 | #1940. Shy Polygons | crimson231 | 100 ✓ | 39ms | 4016kb | C++17 | 13.7kb | 2024-05-29 14:17:27 | 2024-05-29 14:17:28 |
Judging History
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
*/
Details
Tip: Click on the bar to expand more detailed information
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