1 条题解
-
0
这是一道经典的数学构造与模拟题目,属于 POI 2005 的 "Mirror Trap"(镜子陷阱)。
题目分析
-
物理模型转化: 激光器在原点 ,长方体范围为 。 激光在镜面反射,等价于在无限展开的网格空间中沿直线传播。 激光回到原点,意味着在展开空间中,它到达了点 ,其中 为整数。 设激光瞄准点为 ,则方向向量为 。 回到原点的条件是存在时间 使得 。 即 $\frac{a}{x} : \frac{b}{y} : \frac{c}{z} = k : m : n$(整数比)。
-
约束条件:
- 不碰边和顶点:激光路径中不能同时有两个或三个坐标到达边界。这意味着 这三个分数值必须两两不等。
- 最多一个坐标在边界上:如果 且 ,则激光直接打在棱上。所以 中最多有一个等于对应的边界值 。
-
最大化距离: 总距离 。 设 $\frac{a}{x} = \frac{A}{L}, \frac{b}{y} = \frac{B}{L}, \frac{c}{z} = \frac{C}{L}$(通分后),则 。 距离 。 其中 $L = \text{lcm}(\text{den}(\frac{a}{x}), \text{den}(\frac{b}{y}), \text{den}(\frac{c}{z}))$。 分母 。 我们要最大化 。
-
构造策略: 为了让 和 尽可能大, 应该尽可能接近 。 我们只需要在 、、 中枚举 。 共 种组合,检查合法性并计算得分,取最大值即可。
C++ 代码实现
#include <iostream> #include <vector> #include <algorithm> #include <numeric> using namespace std; // 求最大公约数 long long gcd(long long a, long long b) { while (b) { a %= b; swap(a, b); } return a; } // 求最小公倍数 long long lcm(long long a, long long b) { return a / gcd(a, b) * b; } void solve() { long long x, y, z; cin >> x >> y >> z; long long best_score = -1; long long best_a = -1, best_b = -1, best_c = -1; // 枚举 a, b, c 的偏移量 0, 1, 2 for (int da = 0; da <= 2; ++da) { for (int db = 0; db <= 2; ++db) { for (int dc = 0; dc <= 2; ++dc) { long long a = x - da; long long b = y - db; long long c = z - dc; // 1. 检查是否至少为 1 (题目范围 >= 5,减2后 >= 3,此步可省,但为了严谨保留) if (a < 1 || b < 1 || c < 1) continue; // 2. 检查边界值个数,最多只能有一个等于边界值 (否则碰边或顶点) int cnt = (a == x) + (b == y) + (c == z); if (cnt >= 2) continue; // 3. 检查比例是否两两不等 (避免碰边) // a/x == b/y <=> a*y == b*x if (a * y == b * x) continue; if (b * z == c * y) continue; if (a * z == c * x) continue; // 4. 计算得分 Score = L * (a + b + c) long long den_x = x / gcd(a, x); long long den_y = y / gcd(b, y); long long den_z = z / gcd(c, z); long long L = lcm(den_x, lcm(den_y, den_z)); long long score = L * (a + b + c); // 更新最优解 if (score > best_score) { best_score = score; best_a = a; best_b = b; best_c = c; } } } } cout << best_a << " " << best_b << " " << best_c << "\n"; } int main() { // 优化输入输出 ios_base::sync_with_stdio(false); cin.tie(NULL); int k; if (cin >> k) { while (k--) { solve(); } } return 0; }复杂度分析
- 时间复杂度:对于每个测试用例,枚举 种情况。每次计算 和 的时间复杂度为 。总时间复杂度为 ,在 时运算量极小,完全满足时限要求。
- 空间复杂度:,仅需常数级额外空间。
-
- 1
信息
- ID
- 3196
- 时间
- 1000ms
- 内存
- 128MiB
- 难度
- 10
- 标签
- 递交数
- 1
- 已通过
- 0
- 上传者