专栏文章
CF 2138F Ode to the Bridge Builder
CF2138F题解参与者 1已保存评论 0
文章操作
快速查看文章及其快照的属性,并进行相关操作。
- 当前评论
- 0 条
- 当前快照
- 1 份
- 快照标识符
- @minvujnz
- 此快照首次捕获于
- 2025/12/02 09:11 3 个月前
- 此快照最后确认于
- 2025/12/02 09:11 3 个月前
非常好几何题。
最后一部分参考了 Milmon 大神的代码,非常感谢!
最后一部分参考了 Milmon 大神的代码,非常感谢!
首先能够发现 。
又因为题目要求了 ,这说明即使每条边都贴在 上至少也需要 个三角形。
并且每一步都能加一个贴着 三角形是不太现实的,于是我们尝试构造使得每 个三角形能够让与 的距离减掉 。
又因为题目要求了 ,这说明即使每条边都贴在 上至少也需要 个三角形。
并且每一步都能加一个贴着 三角形是不太现实的,于是我们尝试构造使得每 个三角形能够让与 的距离减掉 。
那么尝试让第一个三角形就贴着 ,能够构造出如下的平行四边形式的构造(按字典序为构造顺序):


不过这样有个问题就是当 时,分割出来的 不合法。
对此,因为 ,可以考虑把最后一步的点改为 中点,即:


分析对应的步数,能够发现只需要 步,当 时会恰好等于 ,否则能够多出来一步。
不过这个构造方法肯定不是通用的,现在只保证了 上的线段和 的平行线段的长度,还有 没有考虑。
记 。
首先来考虑 :
使用余弦定理:。
结合 ,可以得到 。
使用余弦定理:。
结合 ,可以得到 。
尝试代入常用角,会发现 都合法,于是至少 内的角都合法。
于是应当要有 。
于是应当要有 。
接下来考虑 :
依然是余弦定理:。
依然是余弦定理:。
首先因为 ,所以 。
接下来把 视作自变量,该二次函数最小值在 取到,又因为 所以可以取到,此时最小值为 (注意此处代入的就是 了),于是 合法。
接下来把 视作自变量,该二次函数最小值在 取到,又因为 所以可以取到,此时最小值为 (注意此处代入的就是 了),于是 合法。
于是只要 ,这个构造就是合法的。
那么如果 怎么办呢?
刚刚的构造其实已经非常好了,我们尝试继续复用这个结构。
刚刚的构造其实已经非常好了,我们尝试继续复用这个结构。
因为这个结构只需要满足 ,于是我们考虑构造一个合法的 出来。
具体来说,发现当 时,可以考虑构造 ;当 时,可以考虑构造 。
具体来说,发现当 时,可以考虑构造 ;当 时,可以考虑构造 。
如图:


对于 ,接下来就可以考虑把 轴变为 直线;对于 。接下来就可以考虑把 轴变为 直线。
在变化之后, 于其对应的 轴的夹角就满足了限制。
在变化之后, 于其对应的 轴的夹角就满足了限制。
不过此时有一个问题是,我们多引入了一个三角形。
当 时,刚好前面的构造还剩了一个可以用上。
不过当 时,就会多出一次步数。
当 时,刚好前面的构造还剩了一个可以用上。
不过当 时,就会多出一次步数。
第一次显然是省不了的,那就只能省掉后面平行四边形的步数了。
不过在叠加的过程,平行四边形的 个三角形看起来是必须的。
那么最后也只能尝试在最后 个三角形进行一些优化了。
不过在叠加的过程,平行四边形的 个三角形看起来是必须的。
那么最后也只能尝试在最后 个三角形进行一些优化了。
也就是说,当剩下的 在 到 之间时,我们需要尝试使用 个三角形进行构造。
首先因为长度 ,所以两个三角形肯定都需要有一条边贴着 。
首先因为长度 ,所以两个三角形肯定都需要有一条边贴着 。
但是这个时候若 近似于 ,似乎不管怎么都构造不出来,好像倒闭了?(我就在这里倒闭了。)
此时回归 的定义,会发现 并不会是个定值,而是会根据 有着不同的取值区间,于是直接认为 是个定值是不正确的。
此时回归 的定义,会发现 并不会是个定值,而是会根据 有着不同的取值区间,于是直接认为 是个定值是不正确的。
那还是继续考虑什么情况 会合法吧。
确定的是,最后一定会有 这条边,并且对于 上选出的第一个三角形的端点 ,一定有 。
于是对于上界,我们只需要考虑 。
于是对于上界,我们只需要考虑 。
还是余弦定理:。
所以这说明 ,推出 。
所以这说明 ,推出 。
那么会发现取 一定满足条件,并且很惊喜的一点是,能够发现 一定时能被构造出的。
当 时,可以取 ;当 时,可以取 。
当 时,可以取 ;当 时,可以取 。
接下来就需要考虑一下 的问题了,因为 的长度都需要合法,所以考虑 长度趋近于 的情况,此时只能选择 为 的中点。
接下来只需要考虑下界的问题了。
- 对于 :,对称轴为 ,结合定义域,当 时取到最小值 。
- 对于 :,对称轴为 ,结合定义域,当 时取到最小值 ,甚至刚刚好。
于是对于上述的情况,只需要取 中点,第一步扩展 ,第二步扩展 ,就解决了这个情况。
时间复杂度为 ,代码非常好写。
CPP#include <bits/stdc++.h>
const double pi = acos(-1);
constexpr int N = 3e5 + 10;
int u[N], v[N];
double sx[N], sy[N];
inline void solve() {
int x, y;
scanf("%d%d%*d", &x, &y);
double d = hypot(x, y);
double th = atan2(y, x);
double sint = 1.0 * y / d;
double cost = 1.0 * x / d;
int a = 1, b = 2, m = 2;
sx[1] = 0.0, sy[1] = 0.0;
sx[2] = 1.0, sy[2] = 0.0;
auto add = [&](double x_, double y_) {
m++;
u[m] = a, v[m] = b;
sx[m] = x_, sy[m] = y_;
return m;
};
if (th > pi / 3) {
b = add(cos(th - pi / 6), sin(th - pi / 6));
}
if (th < pi / 6) {
b = add(cos(th + pi / 6), sin(th + pi / 6));
}
while (d > 2) {
a = add(sx[a] + cost, sy[a] + sint);
b = add(sx[b] + cost, sy[b] + sint);
d -= 1;
}
a = add(sx[a] + d / 2.0 * cost, sy[a] + d / 2.0 * sint);
if ((pi / 6 <= th && th <= pi / 3) || d > 1.5) {
b = add(sx[b] + d / 2.0 * cost, sy[b] + d / 2.0 * sint);
}
a = add(x, y);
printf("%d\n", m - 2);
for (int i = 3; i <= m; i++) {
printf("%d %d %.10lf %.10lf\n", u[i], v[i], sx[i], sy[i]);
}
}
int main() {
int t;
scanf("%d", &t);
while (t--) {
solve();
}
return 0;
}
相关推荐
评论
共 0 条评论,欢迎与作者交流。
正在加载评论...