Official

D - Concentric Circles Editorial by en_translator


The key approach to this problem is not the circle itself, but where the center of the circle can exist.

Let \(O\) be the center of circles \(C_1\) and \(C_2\). Since \(P\) and \(Q\) both lie on the circumference of \(C_1\), it is necessary that:

\[OP = OQ.\]

The set of points whose distance from points \(P\) and \(Q\) are equal is formed by the perpendicular bisector of segment \(PQ\). Thus, \(O\) lies on the perpendicular bisector of segment \(PQ\). (Let this bisector be \(L_1\).)
By applying the same discussions to \(R\) and \(S\), \(O\) lies on the perpendicular bisector of segment \(RS\). (Let this bisector be \(L_2\).)
Hence, \(O\) must line on the intersection of \(L_1\) and \(L_2\). Conversely, if such a point exists, obviously one can place circles \(C_1\) and \(C_2\) satisfying the conditions.
Therefore, the original problem is rephrased into the following:

Does the perpendicular bisector \(L_1\) of segment \(PQ\) and the perpendicular bisector \(L_2\) of segment \(RS\) intersect?

Here, it is a well known fact that:

  • Two lines that are not parallel to each other always intersect.
  • Two different lines that are parallel to each other never intersect.

Thus, the answer to the rephrased problem is:

  1. If \(L_1\) and \(L_2\) are not parallel: the answer is Yes, since two non-parallel lines always intersect.
  2. If \(L_1\) and \(L_2\) are parallel: the answer is Yes if \(L_1\) and \(L_2\) are the same line, and No otherwise.

Now that we identified how to find the answer, all that left is how to compute:

  • whether \(L_1\) and \(L_2\) are parallel, and
  • whether \(L_1\) and \(L_2\) are equal.

To do so, let us find the equation for the lines \(L_1\) and \(L_2\).

We will find the equation of the perpendicular bisector \(L_1\) of segment \(PQ\). Since any point \((x,y)\) on \(L_1\) is equidistant from \(P\) and \(Q\), it must satisfy the following equation:

\[(x-P_x)^2 + (y-P_y)^2 = (x - Q_x)^2 + (y - Q_y)^2,\]

which reduces to

\[2(Q_x - P_x) x + 2 (Q_y - P_y) y + {P_x}^2 + {P_y}^2 - {Q_x}^2 - {Q_y}^2 = 0,\]

an equation of a line with integer coefficients. Likewise, \(L_2\) can be represented by an equation of a line with integer coefficients.

Since the equation is complex, let us define new variables, and represent \(L_1\) and \(L_2\) as \(a_1 x + b_1 y + c_1 = 0\) and \(a_2 x + b_2 y + c_2 = 0\), respectively.

\(L_1\) and \(L_2\) are parallel if and only if \(a_1 b_2 - a_2 b_1 = 0\). Therefore, this criteria allows us to determine if \(L_1\) and \(L_2\) are parallel.
If \(L_1\) and \(L_2\) are parallel, we need to determine if the two lines perfectly overlap. Intuitively, this might seem computable by checking if \(a_1 = a_2, b_1=b_2, c_1=c_2\), but this does not cover the case where \((a_1,b_1,c_1)=(1,2,3), (a_2,b_2,c_2)=(2,4,6)\), where the two lines indeed coincide each other.
There are several resolutions. Here, we will take an approach of normalizing the line. A normalization refers to corresponding one line to one unique representation (called normal form), and turning any lines into that form.
For example, let us say a line \(ax+by+c=0\) is normalized precisely when:

  • \(a,b,c\) are all integers,
  • \(\gcd(a,b,c)=1\),
  • \(a \gt 0\) if \(a \neq 0\), and
  • \(b \gt 0\) if \(a = 0\).

By defining the normal form, any integer-coefficient line has exactly one normal form. Therefore, one can compute \(\mathrm{gcd}\) to normalize \(L_1\) and \(L_2\), then check if \(a_1 = a_2, b_1=b_2, c_1=c_2\), in order to determine if \(L_1\) and \(L_2\) represent the same line.
The problem can be solved by properly implementing these ideas.

  • Sample code (C++)
#include <iostream>
#include <numeric>
#include <tuple>
using namespace std;

tuple<long long, long long, long long> get_canonical(long long px, long long py,
                                                     long long qx,
                                                     long long qy) {
  long long a = 2 * (qx - px);
  long long b = 2 * (qy - py);
  long long c = px * px + py * py - qx * qx - qy * qy;
  long long g = gcd(a, gcd(b, c));
  a /= g, b /= g, c /= g;
  if (a < 0) a = -a, b = -b, c = -c;
  if (a == 0 and b < 0) b = -b, c = -c;
  return {a, b, c};
}

int main() {
  int T;
  cin >> T;
  while (T--) {
    long long px, py, qx, qy, rx, ry, sx, sy;
    cin >> px >> py >> qx >> qy >> rx >> ry >> sx >> sy;
    auto [a1, b1, c1] = get_canonical(px, py, qx, qy);
    auto [a2, b2, c2] = get_canonical(rx, ry, sx, sy);
    if (a1 * b2 - a2 * b1 == 0) {
      if (a1 == a2 and b1 == b2 and c1 == c2) {
        cout << "Yes" << "\n";
      } else {
        cout << "No" << "\n";
      }
    } else {
      cout << "Yes" << "\n";
    }
  }
}

posted:
last update: