#ifndef LOCAL #pragma GCC optimize("O3") #endif #include using namespace std; #define sim template < class c #define ris return * this #define mor > muu & operator << ( #define R22(r) sim > typename \ enable_if<1 r sizeof dud(0), muu&>::type operator<<( c g) { sim > struct rge { c b, e; }; sim > rge range(c h, c n) { return {h, n}; } sim > auto dud(c * r) -> decltype(cerr << *r); sim > char dud(...); struct muu { #ifdef LOCAL stringstream a; ~muu() { cerr << a.str() << endl; } R22(<) a << boolalpha << g; ris; } R22(==) ris << range(begin(g), end(g)); } sim, class b mor pair < b, c> r) { ris << "(" << r.first << ", " << r.second << ")"; } sim mor rge u) { a << "["; for (c i = u.b; i != u.e; ++i) *this << ", " + 2 * (i == u.b) << *i; ris << "]"; } #else sim mor const c&) { ris; } #endif muu & operator()() { ris; } }; #define imie(r...) "[" #r ": " << (r) << "] " #define debug (muu() << __FUNCTION__ << "#" << __LINE__ << ": ") using ld = long double; int n; using ll = long long; using pii = pair; using pld = pair; vector poly; pii S, T, v; pii operator-(pii a, pii b) { return {a.first - b.first, a.second - b.second}; } pii operator+(pii a, pii b) { return {a.first + b.first, a.second + b.second}; } pld operator*(pld v, ld k) { return {v.first * k, v.second * k}; } ll cross(pii a, pii b) { return 1ll * a.first * b.second - 1ll * a.second * b.first; } ll dot(pii a, pii b) { return 1ll * a.first * b.first + 1ll * a.second * b.second; } int sgn(long long x) { if (x > 0) return 1; else if (x < 0) return -1; else return 0; } // czy i przeciecie z odcinkiem [a, a + s] // jak lezy na prostej to false pair przeciecieOdcinek(pii a, pii s) { if (cross(s, v) == 0) return {false, pld()}; int sga = sgn(cross(a, v)); int sgb = sgn(cross(a + s, v)); if (sga * sgb == -1) { pii kk; kk.first = sgn(s.first); kk.second = sgn(s.second); ld t = a.second * kk.first - a.first * kk.second; t /= v.second * kk.first - v.first * kk.second; return {true, v * t}; } else if (sga * sgb == 0) { if (sga == 0) return {true, a}; else if (sgb == 0) return {true, (a + s)}; } return {false, pld()}; } ld norma2; ld dostant(pld x) { return dot(x, v) / norma2; } namespace kasia { typedef pair fun; typedef pair od; typedef pair odi; vector> przedzialy; fun xowa(int sign, int d, pld A) { } fun yowa(int sign, int d, pld A) { ld M = ld t = dostant(A); ld b = M - v.second * t; return {sign * v.second, b}; } const int D = 1e6; const ld eps = 1e-6; // dupe ld dl(od X) { pld x = X.first; pld y = X.second; return sqrt(dot(x - y, x - y)); } bool nonempty(od A) { return dl(A) > eps; } bool nonempty(pld A) { return abs(A.first - A.second) > eps; } od przetnij(vector wiel) { vector res; for (auto o : wiel) { auto p = przeciecieOdcinek(o.first, o.second - o.first); if (p.first) res.push_back(p.second); } sort(res.begin(), res.end()); for (auto i = 0; i +1 < (int)res.size(); i ++) { if (nonempty({res[i], res[i+1]})) return {res[i], res[i+1]}; } return {{0,0}, {0,0}}; } void generuj(int x1, int y1, int x2, int y2) { if (x1 > x2) swap(x1, x2); if (y1 > y2) swap(y1, y2); vector wiel; wiel.push_back({{x1 - D, y2 + D}, {x1, y2}}); if (x1 != x2) wiel.push_back({{x1, y2}, {x2, y2}}); wiel.push_back({{x2, y2}, {x2 + D, y2 + D}}); wiel.push_back({{x2 + D, y2 + D}, {x1 - D, y2 + D}}); od A = przetnij(wiel); debug << A; if (nonempty({dostant(A.first), dostant(A.second)})) przedzialy.push_back({{dostant(A.first), dostant(A.second)}, yowa(1, -y2)}); wiel.clear(); wiel.push_back({{x1 - D, y1 - D}, {x1, y1}}); if (x1 != x2) wiel.push_back({{x1, y1}, {x2, y1}}); wiel.push_back({{x2, y1}, {x2 + D, y1 - D}}); wiel.push_back({{x2 + D, y1 - D}, {x1 - D, y1 - D}}); od B = przetnij(wiel); if (nonempty({dostant(B.first), dostant(B.second)})) przedzialy.push_back({{dostant(B.first), dostant(B.second)}, yowa(-1, y1)}); wiel.clear(); wiel.push_back({{x1 - D, y1 + D}, {x1, y1}}); if (y1 != y2) wiel.push_back({{x1, y1}, {x1, y2}}); wiel.push_back({{x1, y2}, {x1 - D, y2 - D}}); wiel.push_back({{x1 + D, y2 - D}, {x1 - D, y1 - D}}); od C = przetnij(wiel); if (nonempty({dostant(C.first), dostant(C.second)})) przedzialy.push_back({{dostant(C.first), dostant(C.second)}, xowa(-1, x1)}); wiel.clear(); wiel.push_back({{x2 + D, y2 + D}, {x2, y1}}); if (y1 != y2) wiel.push_back({{x1, y1}, {x2, y2}}); wiel.push_back({{x2, y2}, {x2 + D, y2 - D}}); wiel.push_back({{x2 + D, y1 - D}, {x2 + D, y1 + D}}); od E = przetnij(wiel); if (nonempty({dostant(E.first), dostant(E.second)})) przedzialy.push_back({{dostant(E.first), dostant(E.second)}, xowa(1, -x2)}); } void generuj(vector odcinki) { for (auto p : odcinki) generuj(p.first.first, p.first.second, p.second.first, p.second.second); } void generuj() { vector res; for (int i = 0; i + 1 < (int)poly.size(); i ++) { res.push_back({poly[i], poly[i+1]}); } res.push_back({poly.back(), poly[0]}); generuj(res); sort(przedzialy.begin(), przedzialy.end()); } }; int main() { ios_base::sync_with_stdio(0); cin >> n; cin >> S.first >> S.second; cin >> T.first >> T.second; poly.resize(n + 1); for (int i = 0; i < n; ++i) { cin >> poly[i].first >> poly[i].second; } poly[n] = poly[0]; T = T - S; v = T; for (int i = 0; i <= n; ++i) poly[i] = poly[i] - S; S = {0, 0}; // koniec wejscia vector flipy; norma2 = dot(v, v); for (int i = 0; i < n; ++i) { int sa = sgn(cross(v, poly[i])); int sb = sgn(cross(v, poly[i + 1])); if (sa * sb == -1) { ld t; if (poly[i].first == poly[i + 1].first) { // pionowy if (v.first) t = (ld) poly[i].first / v.first; else t = 0; // nie powinno sie stac } else { // poziomy if (v.second) t = (ld) poly[i].second / v.second; else t = 0; // nie powinno sie stac } flipy.push_back(t); } //~ if (sa == 0 && sb == 0) { // pokrywa sie //~ ld t1 = dot(poly[i], v); //~ ld t2 = dot(poly[i + 1], v); //~ t1 /= norma2; //~ t2 /= norma2; //~ if (t1 > t2) swap(t1, t2); //~ flipy.push_back({t1, 1}); //~ flipy.push_back({t2, -1}); //~ } } for (int i = 0; i < n; ++i) { if (cross(v, poly[i]) == 0) { pii przed = (i > 0) ? poly[i - 1] : poly[n - 1]; pii po = poly[i + 1]; int sprzed = sgn(cross(v, przed)); int spo = sgn(cross(v, po)); ld t = dot(poly[i], v); t /= norma2; if (sprzed * spo == -1) { flipy.push_back(t); } else if (sprzed * spo == 0) { if (spo == 0) { if (cross(po - poly[i], przed - poly[i]) > 0) { flipy.push_back(t); } } else if (sprzed == 0) { if (cross(po - poly[i], przed - poly[i]) > 0) { flipy.push_back(t); } } } } } sort (flipy.begin(), flipy.end()); debug << imie(flipy); kasia::generuj(); debug << imie(kasia::przedzialy); for (ld t : flipy) { ld x = t * v.first; ld y = t * v.second; debug << x << ' ' << y; } vector> przedzialy = kasia::przedzialy; map>> mapa; for (auto &u : przedzialy) { mapa[u.second.first].push_back(u); } vector> best; for (auto &dd : mapa) { const vector> &funkcje = dd.second; vector, bool>> evs; for (auto &f : funkcje) { evs.push_back({{f.first.first, f.second}, true}); evs.push_back({{f.first.second, f.second}, false}); } sort (evs.begin(), evs.end()); map mini; for (auto &ev : evs) { if (ev.second == true) { mini[ev.first.second.second]++; } while (true) { auto it = mini.begin(); if (it == mini.end()) break; if (it -> second == 0) { mini.erase(it); } else break; } auto it = mini.begin(); if (it != mini.end()) { best.push_back({ev.first.first, {dd.first, it -> first}}); } } } sort (best.begin(), best.end()); ld last = 1e-8; for (auto &b : best) { } return 0; }