Problem p01320 (C++) — buggy submission, verdict: Time Limit Exceeded

#include <algorithm>
#include <cassert>
#include <cmath>
#include <cstdio>
#include <vector>

#define rep(i, n) for (int i = 0; i < (n); i++)

using namespace std;

const double EPS = 1e-7;
const double PI = acos(-1);

template <class T> struct point {
  T x, y;
  point operator+(const point &a) const { return (point){x + a.x, y + a.y}; }
  point operator-(const point &a) const { return (point){x - a.x, y - a.y}; }
};

template <class T> point<T> operator*(T c, const point<T> &a) {
  return (point<T>){c * a.x, c * a.y};
}

bool operator==(const point<double> &a, const point<double> &b) {
  return abs(a.x - b.x) < EPS && abs(a.y - b.y) < EPS;
}

template <class T> double abs(const point<T> &a) {
  return sqrt(a.x * a.x + a.y * a.y);
}

template <class T> T cross(const point<T> &a, const point<T> &b) {
  return a.x * b.y - a.y * b.x;
}

point<double> rot(const point<double> &a, double theta) {
  return (point<double>){a.x * cos(theta) - a.y * sin(theta),
                         a.x * sin(theta) + a.y * cos(theta)};
}

template <class T> double arg(const point<T> &a) {
  double t = atan2(a.y, a.x);
  return t < 0 ? t + 2 * PI : t;
}

template <class T> struct segment {
  point<T> a, b;
};

enum { CCW = 1, CW = -1, ON = 0 };
int ccw(const point<double> &a, const point<double> &b,
        const point<double> &c) {
  double rdir = cross(b - a, c - a);
  if (rdir > EPS)
    return CCW;
  if (rdir < -EPS)
    return CW;
  return ON;
}

template <class T> double dist(const point<T> &a, const point<T> &b) {
  return sqrt((a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y));
}

bool cover(const segment<double> &S, const point<double> &p) {
  return dist(S.a, p) + dist(p, S.b) < dist(S.a, S.b) + EPS;
}

bool intersect(const segment<double> &S1, const segment<double> &S2) {
  if (max(S1.a.x, S1.b.x) + EPS < min(S2.a.x, S2.b.x) ||
      max(S1.a.y, S1.b.y) + EPS < min(S2.a.y, S2.b.y) ||
      max(S2.a.x, S2.b.x) + EPS < min(S1.a.x, S1.b.x) ||
      max(S2.a.y, S2.b.y) + EPS < min(S1.a.y, S1.b.y))
    return false;
  return ccw(S1.a, S1.b, S2.a) * ccw(S1.a, S1.b, S2.b) <= 0 &&
         ccw(S2.a, S2.b, S1.a) * ccw(S2.a, S2.b, S1.b) <= 0;
}

point<double> get_intersect(const segment<double> &S1,
                            const segment<double> &S2) {
  double a1 = cross(S1.b - S1.a, S2.b - S2.a);
  double a2 = cross(S1.b - S1.a, S1.b - S2.a);
  if (abs(a1) < EPS) {
    if (cover(S1, S2.a))
      return S2.a;
    if (cover(S1, S2.b))
      return S2.b;
    if (cover(S2, S1.a))
      return S1.a;
    return S1.b;
  }
  return S2.a + a2 / a1 * (S2.b - S2.a);
}

int n, m, K;
point<double> P[50]; // 村

point<double> star[50]; // 単位円周を m 等分割した点

vector<pair<double, double>>
    in; // 点が星の内部にあるか判定するための情報. 星の輪郭の各頂点についての
        // <角度,中心からの距離>
point<double>
    in2[100]; // 極座標で書かれた in を直交座標に直したもの ( 高速化のため )

void get_intersect(const point<double> *G1, const point<double> *G2, int &sz,
                   point<double> *res) {
  segment<double> S1[50], S2[50]; // 星の辺
  rep(i, m) {
    S1[i].a = G1[i];
    S1[i].b = G1[(i + K) % m];
    S2[i].a = G2[i];
    S2[i].b = G2[(i + K) % m];
  }
  rep(i, m) rep(j, m) if (intersect(S1[i], S2[j])) res[sz++] =
      get_intersect(S1[i], S2[j]);
}

bool cover(double R, const point<double> &cen, const point<double> &p) {
  // printf("  p=(%.15f, %.15f)\\n",p.x,p.y);
  if (p == cen)
    return true;

  double phi = arg(p - cen), d = dist(p, cen);
  if (d > R + EPS)
    return false;

  if (phi < in[0].first + EPS)
    phi += 2 * PI;
  int i =
      upper_bound(in.begin(), in.end(), make_pair(phi, 0.0)) - in.begin() - 1;
  // printf("    1. (%.3f, %.3f)\\n",R*in2[i].x,R*in2[i].y);
  // printf("    2. (%.3f,
  // %.3f)\\n",R*in2[(i+1)%in.size()].x,R*in2[(i+1)%in.size()].y); printf("    3.
  // (%.3f, %.3f)\\n",(p-cen).x,(p-cen).y); printf("    %f %f
  // %f\\n",R*in[i].second,R*in[(i+1)%in.size()].second,d);
  return ccw(R * in2[i], R * in2[(i + 1) % in.size()], p - cen) != CW;
}

// p1, p2 : 星の境界上にある二つの村
bool check(double R, const point<double> &p1, const point<double> &p2) {
  point<double> G1[50], G2[50]; // 星を上下反転させて, それぞれ p1, p2
                                // が中心に来るように平行移動したもの
  rep(k, m) {
    point<double> p = R * (point<double>){star[k].x, -star[k].y};
    G1[k] = p + p1;
    G2[k] = p + p2;
  }

  int sz = 0;
  static point<double> Q[50 * 50]; // 星の中心の候補点
  get_intersect(G1, G2, sz, Q);
  Q[sz++] = (point<double>){0, 0};
  // printf("R=%f\\n",R);
  // printf("sz=%d\\n",sz);
  // rep(k,sz){
  // printf("(%.15f, %.15f)\\n",Q[k].x,Q[k].y);
  // }

  rep(k, sz) {
    // printf("k=%d:\\n",k);
    bool ok = true;
    rep(l, n) if (!cover(R, Q[k], P[l])) {
      ok = false;
      break;
    }
    if (ok)
      return true;
  }
  return false;
}

int main() {
  for (; scanf("%d%d%d", &n, &m, &K), n;) {
    // fprintf(stderr,"n=%d, m=%d, K=%d:\\n",n,m,K);
    // if(K==24) break;
    rep(i, n) scanf("%lf%lf", &P[i].x, &P[i].y);

    rep(i, m) star[i] = rot((point<double>){1, 0}, 2 * i * PI / m + PI / 2);

    in.clear();
    rep(i, m) {
      in.push_back(make_pair(arg(star[i]), abs(star[i])));
      if (K > 1) {
        segment<double> S1 = {star[i], star[(i + K) % m]};
        segment<double> S2 = {star[(i + 1) % m], star[(i + 1 - K + m) % m]};
        assert(intersect(S1, S2));
        point<double> p = get_intersect(S1, S2);
        in.push_back(make_pair(arg(p), abs(p)));
      }
    }
    sort(in.begin(), in.end());
    rep(i, in.size()) {
      in2[i].x = in[i].second * cos(in[i].first);
      in2[i].y = in[i].second * sin(in[i].first);
    }

    double ans = 1e4;
    rep(i, n) for (int j = i + 1; j < n; j++) { // 星の境界上の二点を決めうち
                                                // if(i==0&&j==1);else continue;
      // double R=1335.325241088867188;
      // R=ans;
      // printf("! %d\\n",check(R,P[0],P[1])); return 0;
      if (!check(ans + EPS, P[i], P[j]))
        continue; // 解がよくなる見込みがないので二分探索しない

      double lo = 0, hi = ans;
      while (hi - lo > 1e-7) {
        double mi = (lo + hi) / 2;
        if (check(mi, P[i], P[j]))
          hi = mi;
        else
          lo = mi;
      }
      ans = lo;
      // fprintf(stderr,"  ans=%f\\n",ans);
    }

    printf("%.9f\\n", ans);
  }

  return 0;
}

Error: TLE

Fixed submission:

#include <algorithm>
#include <cassert>
#include <cmath>
#include <cstdio>
#include <vector>

#define rep(i, n) for (int i = 0; i < (n); i++)

using namespace std;

const double EPS = 1e-8;
const double PI = acos(-1);

template <class T> struct point {
  T x, y;
  point operator+(const point &a) const { return (point){x + a.x, y + a.y}; }
  point operator-(const point &a) const { return (point){x - a.x, y - a.y}; }
};

template <class T> point<T> operator*(T c, const point<T> &a) {
  return (point<T>){c * a.x, c * a.y};
}

bool operator==(const point<double> &a, const point<double> &b) {
  return abs(a.x - b.x) < EPS && abs(a.y - b.y) < EPS;
}

template <class T> double abs(const point<T> &a) {
  return sqrt(a.x * a.x + a.y * a.y);
}

template <class T> T cross(const point<T> &a, const point<T> &b) {
  return a.x * b.y - a.y * b.x;
}

point<double> rot(const point<double> &a, double theta) {
  return (point<double>){a.x * cos(theta) - a.y * sin(theta),
                         a.x * sin(theta) + a.y * cos(theta)};
}

template <class T> double arg(const point<T> &a) {
  double t = atan2(a.y, a.x);
  return t < 0 ? t + 2 * PI : t;
}

template <class T> struct segment {
  point<T> a, b;
};

enum { CCW = 1, CW = -1, ON = 0 };
int ccw(const point<double> &a, const point<double> &b,
        const point<double> &c) {
  double rdir = cross(b - a, c - a);
  if (rdir > EPS)
    return CCW;
  if (rdir < -EPS)
    return CW;
  return ON;
}

template <class T> double dist(const point<T> &a, const point<T> &b) {
  return sqrt((a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y));
}

bool cover(const segment<double> &S, const point<double> &p) {
  return dist(S.a, p) + dist(p, S.b) < dist(S.a, S.b) + EPS;
}

bool intersect(const segment<double> &S1, const segment<double> &S2) {
  if (max(S1.a.x, S1.b.x) + EPS < min(S2.a.x, S2.b.x) ||
      max(S1.a.y, S1.b.y) + EPS < min(S2.a.y, S2.b.y) ||
      max(S2.a.x, S2.b.x) + EPS < min(S1.a.x, S1.b.x) ||
      max(S2.a.y, S2.b.y) + EPS < min(S1.a.y, S1.b.y))
    return false;
  return ccw(S1.a, S1.b, S2.a) * ccw(S1.a, S1.b, S2.b) <= 0 &&
         ccw(S2.a, S2.b, S1.a) * ccw(S2.a, S2.b, S1.b) <= 0;
}

point<double> get_intersect(const segment<double> &S1,
                            const segment<double> &S2) {
  double a1 = cross(S1.b - S1.a, S2.b - S2.a);
  double a2 = cross(S1.b - S1.a, S1.b - S2.a);
  if (abs(a1) < EPS) {
    if (cover(S1, S2.a))
      return S2.a;
    if (cover(S1, S2.b))
      return S2.b;
    if (cover(S2, S1.a))
      return S1.a;
    return S1.b;
  }
  return S2.a + a2 / a1 * (S2.b - S2.a);
}

int m, K;
vector<pair<double, double>>
    in; // 点が星の内部にあるか判定するための情報. 星の輪郭の各頂点についての
        // <角度,中心からの距離>
point<double>
    in2[100]; // 極座標で書かれた in を直交座標に直したもの ( 高速化のため )

void get_intersect(const point<double> *G1, const point<double> *G2, int &sz,
                   point<double> *res) {
  segment<double> S1[50], S2[50]; // 星の辺
  rep(i, m) {
    S1[i].a = G1[i];
    S1[i].b = G1[(i + K) % m];
    S2[i].a = G2[i];
    S2[i].b = G2[(i + K) % m];
  }
  rep(i, m) rep(j, m) if (intersect(S1[i], S2[j])) res[sz++] =
      get_intersect(S1[i], S2[j]);
}

bool cover(double R, const point<double> &cen, const point<double> &p) {
  if (p == cen)
    return true;

  double phi = arg(p - cen), d = dist(p, cen);
  if (d > R + EPS)
    return false;

  if (phi < in[0].first + EPS)
    phi += 2 * PI;
  int i =
      upper_bound(in.begin(), in.end(), make_pair(phi, 0.0)) - in.begin() - 1;
  return ccw(R * in2[i], R * in2[(i + 1) % in.size()], p - cen) != CW;
}

int main() {
  for (int n; scanf("%d%d%d", &n, &m, &K), n;) {
    // fprintf(stderr,"n=%d, m=%d, K=%d:\\n",n,m,K);
    // if(K==24) break;
    point<double> P[50];
    rep(i, n) scanf("%lf%lf", &P[i].x, &P[i].y);

    point<double> star[50];
    rep(i, m) star[i] = rot((point<double>){1, 0}, 2 * i * PI / m + PI / 2);

    in.clear();
    rep(i, m) {
      in.push_back(make_pair(arg(star[i]), abs(star[i])));
      if (K > 1) {
        segment<double> S1 = {star[i], star[(i + K) % m]};
        segment<double> S2 = {star[(i + 1) % m], star[(i + 1 - K + m) % m]};
        assert(intersect(S1, S2));
        point<double> p = get_intersect(S1, S2);
        in.push_back(make_pair(arg(p), abs(p)));
      }
    }
    sort(in.begin(), in.end());
    rep(i, in.size()) {
      in2[i].x = in[i].second * cos(in[i].first);
      in2[i].y = in[i].second * sin(in[i].first);
    }

    double lo = 0, hi = 1e4;
    while (hi - lo > 1e-7) {
      double mi = (lo + hi) / 2, R = mi;
      // fprintf(stderr,"  lo=%f, hi=%f\\n",lo,hi);
      point<double> G[50]; // 星を上下反転させたもの
      rep(i, m) { G[i] = R * (point<double>){star[i].x, -star[i].y}; }

      bool cov = false; // Q のある点を中心とする星ですべての村が覆えるか
      rep(i, n) for (int j = i + 1; j < n; j++) {
        point<double> G1[50], G2[50];
        rep(k, m) {
          G1[k] = G[k] + P[i];
          G2[k] = G[k] + P[j];
        }

        int sz = 0;
        static point<double> Q[50 * 50]; // 星の中心の候補点
        get_intersect(G1, G2, sz, Q);

        rep(k, sz) {
          bool ok = true;
          rep(l, n) if (!cover(R, Q[k], P[l])) {
            ok = false;
            break;
          }
          if (ok) {
            cov = true;
            goto FOUND;
          }
        }
      }

    FOUND:
      if (cov)
        hi = mi;
      else
        lo = mi;
    }

    printf("%.9f\\n", (lo + hi) / 2);
  }

  return 0;
}