結果
問題 | No.96 圏外です。 |
ユーザー | codershifth |
提出日時 | 2015-08-04 23:03:25 |
言語 | C++11 (gcc 11.4.0) |
結果 |
RE
|
実行時間 | - |
コード長 | 7,935 bytes |
コンパイル時間 | 2,122 ms |
コンパイル使用メモリ | 182,564 KB |
実行使用メモリ | 6,948 KB |
最終ジャッジ日時 | 2024-07-18 01:20:40 |
合計ジャッジ時間 | 7,213 ms |
ジャッジサーバーID (参考情報) |
judge3 / judge2 |
(要ログイン)
テストケース
テストケース表示入力 | 結果 | 実行時間 実行使用メモリ |
---|---|---|
testcase_00 | AC | 2 ms
5,248 KB |
testcase_01 | AC | 3 ms
5,376 KB |
testcase_02 | AC | 2 ms
5,376 KB |
testcase_03 | AC | 2 ms
5,376 KB |
testcase_04 | RE | - |
testcase_05 | RE | - |
testcase_06 | RE | - |
testcase_07 | RE | - |
testcase_08 | RE | - |
testcase_09 | RE | - |
testcase_10 | RE | - |
testcase_11 | RE | - |
testcase_12 | RE | - |
testcase_13 | RE | - |
testcase_14 | RE | - |
testcase_15 | RE | - |
testcase_16 | RE | - |
testcase_17 | RE | - |
testcase_18 | RE | - |
testcase_19 | RE | - |
testcase_20 | RE | - |
testcase_21 | RE | - |
testcase_22 | RE | - |
testcase_23 | RE | - |
testcase_24 | RE | - |
testcase_25 | RE | - |
testcase_26 | RE | - |
testcase_27 | RE | - |
ソースコード
#include <bits/stdc++.h> typedef long long ll; typedef unsigned long long ull; #define FOR(i,a,b) for(int (i)=(a);i<(b);i++) #define REP(i,n) FOR(i,0,n) #define RANGE(vec) (vec).begin(),(vec).end() using namespace std; template<typename T> struct Pt { T x, y; Pt(T x0, T y0) : x(x0), y(y0) {} Pt() :x(0),y(0) {} Pt(const Pt &other) :x(other.x),y(other.y) {} Pt &operator=(const Pt& other) { x = other.x; y = other.y; return *this; } const Pt operator+(const Pt &other) const { return Pt(other.x+x, other.y+y); } const Pt operator-(const Pt &other) const { return Pt(other.x-x, other.y-y); } Pt &operator+=(const Pt &other) { x += other.x; y += other.y; return *this; } Pt &operator-=(const Pt &other) { x -= other.x; y -= other.y; return *this; } Pt operator*(double r) const { return Pt(x*r, y*r); } bool operator==(const Pt &other) const { return (x==other.x && y==other.y); } bool operator!=(const Pt &other) const { return !(operator==(other)); } bool operator<(const Pt &other) const { return (x < other.x)? true : ((x==other.x)? (y < other.y) : false); } bool operator<=(const Pt &other) const { return (*this == other)? true : (*this < other); } bool operator>(const Pt &other) const { return (other < *this); } bool operator>=(const Pt &other) const { return (other <= *this); } double norm(void) const { return hypot(x, y); } // class method static double cross(const Pt &a, const Pt &b) { return ((double)a.y*b.x - (double)a.x*b.y); } static double dot(const Pt &a, const Pt &b) { return (double)a.x*b.x+(double)a.y*b.y; } // O(n*log(n)) static std::vector<Pt> convex_hull(std::vector<Pt> &ps) { std::sort(ps.begin(), ps.end()); int k = 0; int n = ps.size(); vector<Pt> qs(2*n); for (int i = 0; i < n; ++i) { while (k > 1 && cross(qs[k-1]-qs[k-2], ps[i]-qs[k-1]) <= 0) --k; qs[k++] = ps[i]; } for (int i = n-2, t = k; i >= 0; --i) { while (k > t && cross(qs[k-1]-qs[k-2], ps[i]-qs[k-1]) <= 0) --k; qs[k++] = ps[i]; } qs.resize(k-1); qs.shrink_to_fit(); return std::move(qs); } // convex_diameter // O(n*log(n)) static double convex_diameter(std::vector<Pt> &ps) { auto qs = convex_hull(ps); int n = qs.size(); auto dist = [](const Pt &a, const Pt &b) { return sqrt(dot(a-b, a-b)); }; if (n == 2) return dist(qs[0], qs[1]); int i,j; i = j = 0; for (int k = 0; k < n; ++k) { if ( !(qs[i] < qs[k]) ) i = k; if (qs[j] < qs[k]) j = k; } double res = 0; int si = i, sj = j; while ( !(i == sj && j == si) ) { res = max(res, dist(qs[i], qs[j])); int di = (i+1)%n; int dj = (j+1)%n; if (cross(qs[di]-qs[i], qs[dj]-qs[j]) < 0) i = di; else j = dj; } return res; } friend std::ostream &operator<<(std::ostream &os, const Pt &p) { os <<"("<<p.x<<","<<p.y<<")"; return os; } }; template<typename T> Pt<T> operator*(double r, const Pt<T> &p) { return p*r; } class UFTree { std::vector<int> par_; std::vector<int> rank_; int size_; public: UFTree(int N) { init(N); } UFTree() {} ~UFTree() {} void init(int N) { par_.resize(N); rank_.resize(N, 0); for (int i = 0; i < N; ++i) par_[i] = i; size_ = N; } int find(int x) { assert(0 <= x && x < par_.size()); if ( par_[x] == x ) return x; else return ( par_[x] = find(par_[x])); } void unite(int x, int y) { assert(0 <= x && x < par_.size()); assert(0 <= y && y < par_.size()); x = find(x); y = find(y); if ( x == y ) return; --size_; if ( rank_[x] < rank_[y] ) par_[x] = y; else { par_[y] = x; if ( rank_[x] == rank_[y] ) ++rank_[x]; } } bool same(int x, int y) { return (find(x) == find(y)); } size_t size() { return size_; } // find 経由で par を更新してからでないと par へのアクセスは危険 int operator[](size_t i) { return find(i); } }; class NoService { public: void solve(void) { int N; cin>>N; // 中継局がないときは 1km if (N==0) { cout<<1<<endl; return; } // // Easy と違って N <= 120000 なので O(N^2) では間に合わない // 距離が 10 km 以内の中継局を同じグループとして、中継局をグループ化してやることが // できれば、凸包を作って(O(n*log(n)) からキャリパー法 (O(n)) が使える。 // // union find 自体は高速なので、問題は (x,y) の周り 10km の (x',y') をどう求めるか // が問題となる。10km 以内の中継局を同じグループとみなすので、座標 x,y を // 10km x 10km のバケットで管理するバケット法を使う。 // // 座標は整数なので 1 バケットに最大 100 個の点が入る。 // (x,y) の周囲 10km 以内の点を見つけるのには (x,y) の所属するバケット周りの 9 バケット // (最大 900 点)をチェックすればよい。 // // O(N*900) <= 108000000 // // 制限時間 5 秒なのでなんとかまにあいそう? // // x,y の制限が小さいので配列でバケットが作れる (access O(1)) vector<vector<vector<int>>> bucket(201,vector<vector<int>>(201, vector<int>())); UFTree uft(N); const int offset = 1000; const int dx[] = {-1,0,1}; const int dy[] = {-1,0,1}; vector<Pt<int>> ps; REP(i,N) { int x,y; cin>>x>>y; ps.emplace_back(x,y); bucket[(x+offset)/10][(y+offset)/10].push_back(i); } // bucket を使って UFTree を更新 REP(i,N) { int xi = (ps[i].x+offset)/10; int yi = (ps[i].y+offset)/10; // 隣接する 9 バケットを探索 REP(ii,3) REP(jj,3) { int xi2 = xi+dx[ii]; int yi2 = yi+dy[jj]; if (xi2 < 0 || xi2 > 200 || yi2 < 0 || yi2 > 200) continue; for (auto k : bucket[xi2][yi2]) { if ( (ps[k]-ps[i]).norm() <= 10 ) uft.unite(k,i); } } } vector<vector<Pt<int>>> group(N); REP(i,N) group[uft[i]].push_back(ps[i]); double ans = 0; REP(i,N) { if (uft[i]==i) ans = max(ans, Pt<int>::convex_diameter(group[uft[i]])); } cout<<setprecision(20)<<ans+2<<endl; } }; #if 1 int main(int argc, char *argv[]) { ios::sync_with_stdio(false); auto obj = new NoService(); obj->solve(); delete obj; return 0; } #endif