HDU7146. Laser (2022杭电多校第1场I题)
HDU7146. Laser (2022杭电多校第1场I题)
题意
给出二维平面上有 \(n\) 个点的坐标,第 \(i\) 个点的坐标为 \((x_i, y_i)\),现要在二维平面上找一点 \((x, y)\),使得以该点为中心的米字型射线能够覆盖所有的 \(n\) 个点。输出是否可以找到这样的点。
米字型射线的定义:从中心向0,45,90,135,180,225,270,315度方向角的射线。
分析
先考察第 \(1\) 个点与其他所有点的关系,如果所有点都满足米字型射线所包含的斜率(\(0,-1,1,\infty\)),则已经找到答案,输出 YES
。
如果存在 \(1\) 个点与第 \(1\) 个点的关系不满足米字型射线,则找到了一对斜率不是 \(0,-1,1\) 的点对,容易发现,若要构造一个米字型射线,使得这两个点被覆盖,只有有限个中心可以作为答案。
经过缜密的计算,共有 \(12\) 个点,满足条件,不妨设要被覆盖的 \(2\) 个点为 \((x_1,y_1),(x_2,y_2)\),则 \(12\) 个可能的中心为:
\[ (x_2,y_1)\\
(x_1,y_2)\\
\left(\frac{y_2-y_1+x_1+x_2}{2},\frac{x_2-x_1+y_1+y_2}{2}\right)\\
\left(\frac{y_1-y_2+x_1+x_2}{2},\frac{x_1-x_2+y_1+y_2}{2}\right)\\
\left(x_1-y_1+y_2,y_2\right)\\
\left(x_2-y_2+y_1,y_1\right)\\
\left(x_2-y_1+y_2,y_1\right)\\
\left(x_1-y_2+y_1,y_2\right)\\
\left(x_2, x_1-x_2+y_1\right)\\
\left(x_1, x_2-x_1+y_2\right)\\
\left(x_1, x_1-x_2+y_2\right)\\
\left(x_2, x_2-x_1+y_1\right)\\
\]
我们可以分别以 \(O(n)\) 的时间复杂度检验这 \(12\) 个中心(方法和一开始考察第 \(1\) 个点与其他所有点的关系相同),如果这 \(12\) 个中心没有一个满足条件,输出 NO
,否则输出 YES
。
时间复杂度为 \(O(12n)\)
代码
#include <iostream>
using namespace std;
typedef long long Lint;
const int maxn = 5e5 + 10;
Lint x[maxn], y[maxn];
int n;
bool check(Lint x1, Lint y1, Lint x2, Lint y2) {
if (x1 == x2)
return true;
if (y1 == y2)
return true;
if (abs(x1 - x2) == abs(y1 - y2))
return true;
return false;
}
bool is_ok(Lint xx, Lint yy) {
for (int i = 1; i <= n; i++) {
if (!check(xx, yy, x[i], y[i])) {
return false;
}
}
return true;
}
void solve() {
cin >> n;
for (int i = 1; i <= n; i++) {
cin >> x[i] >> y[i];
x[i] <<= 1;
y[i] <<= 1;
}
int pos = 0;
for (int i = 2; i <= n; i++) {
if (!check(x[1], y[1], x[i], y[i])) {
pos = i;
break;
}
}
if (pos == 0) {
cout << "YES\n";
return;
}
pair<Lint, Lint> V[] = {{x[pos], y[1]},
{x[1], y[pos]},
{(y[pos] - y[1] + x[1] + x[pos]) / 2, (x[pos] - x[1] + y[1] + y[pos]) / 2},
{(y[1] - y[pos] + x[1] + x[pos]) / 2, (x[1] - x[pos] + y[1] + y[pos]) / 2},
{x[1] - y[1] + y[pos], y[pos]},
{x[pos] - y[pos] + y[1], y[1]},
{x[pos] - y[1] + y[pos], y[1]},
{x[1] - y[pos] + y[1], y[pos]},
{x[pos], x[1] - x[pos] + y[1]},
{x[1], x[pos] - x[1] + y[pos]},
{x[1], x[1] - x[pos] + y[pos]},
{x[pos], x[pos] - x[1] + y[1]}};
for (auto it : V) {
Lint x = it.first, y = it.second;
if (is_ok(x, y)) {
cout << "YES\n";
return;
}
}
cout << "NO\n";
}
int main() {
ios::sync_with_stdio(0);
cin.tie(0);
int T;
cin >> T;
while (T--)
solve();
return 0;
}