Problem p01649 (C++) — buggy submission, verdict: Runtime Error

#include <bits/stdc++.h>
#define REP(i, n) for (int i = 0; i < (int)(n); ++i)

using namespace std;
typedef complex<double> P;
typedef const P &rP;
typedef vector<P> L;
P vec(L l) { return l[1] - l[0]; }

const double EPS = 1e-8;

int sign(double x) { return x > EPS ? 1 : x < -EPS ? -1 : 0; }
double dot(P a, P b) { return real(conj(a) * b); }
double cross(P a, P b) { return imag(conj(a) * b); }

int ccw(P a, P b, P c) {
  b -= a;
  c -= a;
  return sign(cross(b, c)) ?: dot(b, c) < 0 ? 2 : norm(b) < norm(c) ? -2 : 0;
}

bool iSS(L s, L t) {
  auto ok = [](L a, L b) {
    return ccw(a[0], a[1], b[0]) * ccw(a[0], a[1], b[1]) <= 0;
  };
  return ok(s, t) && ok(t, s);
}

vector<P> pLL(L l, L m) {
  double A = cross(vec(l), vec(m));
  double B = cross(vec(l), l[1] - m[0]);
  if (sign(A) == 0 && sign(B) == 0)
    return {l[0], l[1], m[0], m[1]}; // 二直線が重なっている
  if (sign(A) == 0)
    return {}; // 直線が交わらない
  return {m[0] + vec(m) * B / A};
}

typedef P Point;
typedef L Line;
const double MAX_D = 10000;
Point input() {
  double x, y;
  cin >> x >> y;
  return {x, y};
}

double calc(Point p, Point v, Point q, double r) {
  p -= q;
  // ((p) + vt) ^ 2 == (r + r) ^ 2
  // v^2 * t^2 + 2vp * t + p^2 - 4r^2 == 0
  double a = norm(v);
  double b = 2.0 * dot(v, p);
  double c = norm(p) - 4.0 * r * r;
  double D = b * b - 4.0 * a * c;
  if (D < -EPS)
    return DBL_MAX;
  if (D < 0)
    D = 0;
  double t1 = (-b - sqrt(D)) / (2.0 * a);
  double t2 = (-b + sqrt(D)) / (2.0 * a);
  if (t1 > 0)
    return t1;
  if (t2 > 0)
    return t2;
  return DBL_MAX;
}

int main() {
  int n;
  while (cin >> n && n > 0) {
    double w, h, r, vx, vy;
    cin >> w >> h >> r >> vx >> vy;

    vector<Line> walls;
    walls.push_back({{r, r}, {w - r, r}});
    walls.push_back({{w - r, r}, {w - r, h - r}});
    walls.push_back({{w - r, h - r}, {r, h - r}});
    walls.push_back({{r, h - r}, {r, r}});

    P sp = input();
    P vp = {vx, vy};
    vp *= 2000.0 / abs(vp);

    vector<Point> balls;
    REP(i, n - 1) { balls.push_back(input()); }

    int ans = -1;
    double total = 0;
    while (true) {
      Line l = {sp, sp + vp};
      // cout << l[0] << " " << l[1] << endl;

      P cp = {-1, -1};
      P nvp = vp;

      REP(i, walls.size()) if (iSS(l, walls[i])) {
        auto v = pLL(l, walls[i]);
        if (v.size() != 1)
          continue; // wwwwwwwww
        auto c = v.front();
        if (abs(c - sp) < EPS)
          continue;
        cp = c;
        if (i % 2 == 0) {
          double x = nvp.real();
          double y = nvp.imag() * -1;
          nvp = {x, y};
        }
        if (i % 2 == 1) {
          double x = nvp.real() * -1;
          double y = nvp.imag();
          nvp = {x, y};
        }
        break;
      }

      assert(cp.real() != -1);

      vector<pair<double, int>> events;
      REP(i, balls.size()) {
        double t = calc(sp, vp, balls[i], r);
        double d = abs(vp * t) / abs(cp - sp);
        assert(d >= 0.0);
        if (d < 1.0) {
          events.push_back(make_pair(d, i));
        }
      }
      sort(events.begin(), events.end());

      if (events.size() >= 1) {
        auto d = events.front().first * abs(cp - sp);
        if (total + d <= MAX_D - EPS) {
          ans = events.front().second + 2;
        }
        break;
      }

      total += abs(cp - sp);
      sp = cp;
      vp = nvp;

      if (total >= MAX_D - EPS)
        break;
    }

    cout << ans << endl;
  }
  return 0;
}

Error: 0

Fixed submission:

#include <bits/stdc++.h>
#define REP(i, n) for (int i = 0; i < (int)(n); ++i)

using namespace std;
typedef complex<double> P;
const double EPS = 1e-8;
double dot(P a, P b) { return real(conj(a) * b); }
double cross(P a, P b) { return imag(conj(a) * b); }
int sign(double x) { return x > EPS ? 1 : x < -EPS ? -1 : 0; }

typedef vector<P> L;
P vec(L l) { return l[1] - l[0]; }
struct C {
  P p;
  double r;
};

P proj(L l, P p) {
  double t = dot(p - l[0], vec(l)) / norm(vec(l));
  return l[0] + t * vec(l);
}

int ccw(P a, P b, P c) {
  b -= a;
  c -= a;
  return sign(cross(b, c)) ?: dot(b, c) < 0 ? 2 : norm(b) < norm(c) ? -2 : 0;
}

vector<P> pCL(C c, L l) {
  vector<P> res;
  P center = proj(l, c.p);
  double d = abs(center - c.p);
  double tt = c.r * c.r - d * d;
  if (tt < 0 && tt > -EPS)
    tt = 0;
  if (tt < 0)
    return res;
  double t = sqrt(tt);
  P vect = vec(l);
  vect /= abs(vect);
  res.push_back(center - vect * t);
  if (t > EPS) {
    res.push_back(center + vect * t);
  }
  return res;
}

typedef P Point;
typedef L Line;
typedef C Circle;

P input() {
  double x, y;
  cin >> x >> y;
  return {x, y};
}

bool iSS(L s, L t) {
  auto ok = [](L a, L b) {
    return ccw(a[0], a[1], b[0]) * ccw(a[0], a[1], b[1]) <= 0;
  };
  return ok(s, t) && ok(t, s);
}

vector<P> pLL(L l, L m) {
  double A = cross(vec(l), vec(m));
  double B = cross(vec(l), l[1] - m[0]);
  if (sign(A) == 0 && sign(B) == 0)
    return {l[0], l[1], m[0], m[1]}; // 二直線が重なっている
  if (sign(A) == 0)
    return {}; // 直線が交わらない
  return {m[0] + vec(m) * B / A};
}

const double MAX_D = 10000;

int main() {
  int n;
  while (cin >> n && n > 0) {
    double w, h, r, vx, vy;
    cin >> w >> h >> r >> vx >> vy;
    vector<Line> walls;
    walls.push_back({{0, 0}, {w, 0}});
    walls.push_back({{w, 0}, {w, h}});
    walls.push_back({{w, h}, {0, h}});
    walls.push_back({{0, h}, {0, 0}});

    P sp = input();
    P vp = {vx, vy};
    vp *= 10000.0 / abs(vp);

    vector<Circle> balls;
    REP(i, n - 1) {
      Circle c = {input(), r};
      balls.push_back(c);
    }

    int ans = -1;
    double total = 0;
    while (true) {
      Line l = {sp, sp + vp};

      P cp = {-1, -1};
      P nvp = vp;

      // cout << l[0] << " " << l[1] << endl;

      REP(i, walls.size()) if (iSS(l, walls[i])) {
        auto v = pLL(l, walls[i]);
        if (v.size() != 1)
          continue; // wwwwwwwww
        auto c = v.front();
        if (abs(c - sp) < EPS)
          continue;
        cp = c;
        if (i % 2 == 0)
          nvp.imag(nvp.imag() * -1);
        if (i % 2 == 1)
          nvp.real(nvp.real() * -1);
      }

      assert(cp.real() != -1);

      vector<pair<double, int>> events;
      REP(i, balls.size()) {
        auto cv = pCL(balls[i], l);
        for (auto p : cv) {
          double d = abs(p - sp) / abs(cp - sp);
          assert(d >= 0.0 - EPS && d <= 1.0 + EPS);
          events.push_back(make_pair(d, i));
        }
      }
      sort(events.begin(), events.end());

      if (events.size() >= 1) {
        auto d = events.front().first * abs(cp - sp);
        if (total + d <= MAX_D + EPS) {
          ans = events.front().second + 2;
          break;
        }
      }

      total += abs(cp - sp);
      sp = cp;
      vp = nvp;

      if (total >= MAX_D + EPS)
        break;
    }

    cout << ans << endl;
  }
  return 0;
}