1 条题解
-
0
思路与算法
设人与灯泡的水平距离为x。影子尚未碰墙时,地面影长是hx/(H-h),随x增大。碰墙边界x0=D(H-h)/H;碰墙后,地面到墙距离与墙面影长之和为f(x)=D-x+H-(H-h)D/x。该段二阶导数为负,驻点x=sqrt((H-h)D)。把x夹到[x0,D],计算f,并与边界地面影长D*h/H取较大值。
正确性说明
相似三角形给出影子在墙面处的高度H-(H-h)*D/x,正好在x=x0时为0。碰墙之前影长单调增,所以只需考虑边界;碰墙之后f为严格凹函数,其导数为-1+(H-h)*D/x²,最大值在驻点或夹取后的端点。两个分段的最大值比较即整个允许位置区间的最大影长。
复杂度
每组固定次数算术与一次平方根,时间O(1),空间O(1),变量初始化O(1)。T≤100,总时间O(T)。使用long double,输出三位小数;H-h≥0.01保证分母不为0。
易错点
影长包含地面与墙面两部分,不能只算地面延长线。驻点必须限制在碰墙区间,直接代入未夹取值会出错。独立核验使用分段几何函数的数值最优化,同时比较全部端点;测试含最小高度差、极短距离及大尺寸。
参考代码(C++11)
#include <bits/stdc++.h> using namespace std; int main() { int T; cin >> T; cout << fixed << setprecision(3); while (T--) { long double H, h, D; cin >> H >> h >> D; long double low = D * (H - h) / H; long double x = max(low, min(D, sqrtl((H - h) * D))); long double ans = max(D * h / H, D - x + H - (H - h) * D / x); cout << ans << '\n'; } }
- 1