1 条题解

  • 0
    @ 2026-10-26 13:00:02

    思路与算法

    设人与灯泡的水平距离为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

    信息

    ID
    1737
    时间
    1000ms
    内存
    64MiB
    难度
    普及
    标签
    递交数
    1
    已通过
    1
    上传者