1 条题解

  • 0
    @ 2026-10-27 12:58:43

    思路与算法

    设圆心角的一半为θ,弦长L=2Rsinθ,弧长L′=2Rθ,因此sinθ/θ=1/(1+d),d=nC。短弧θ∈[0,π/2],对loss(θ)=1−sinθ/θ二分,使其等于d/(1+d)。最终弓高h=(L/2)tan(θ/2)。很小角度直接相减会丢精度,此时用θ²/6−θ⁴/120+θ⁶/5040−…计算loss。L=0或d=0直接输出0。

    正确性说明

    圆弧与弦长关系导出上述方程。对0<θ≤π/2,sinθ−θcosθ的导数为θsinθ>0,故θ/sinθ严格递增,loss也严格递增。d≤0.5时所需弧弦比≤1.5<π/2,唯一解落在二分区间。每次按loss比较保留包含真解的一半;120步后二分误差足够小。h=R(1−cosθ)用半角式改写,避免小角相减。小角级数为交错递减项,20项截断远小于公开误差;long double计算与三位输出满足约定容差。

    复杂度

    初始化O(1),120次二分,每次至多20项级数或一次正弦,均为固定次数,总时间O(1),额外空间O(1)。若按目标二分精度δ计,为O(log(1/δ))次判定。

    易错点

    圆弧不是抛物线;所求为弓高,不是半径。L0和零膨胀单独处理。微小d下1−sinθ/θ会抵消,应采用级数;输出使用题面公开绝对误差,不机械逐字比较舍入串。

    参考代码(C++11)

    #include <bits/stdc++.h>
    using namespace std;
    long double loss(long double theta) {
        if (theta < 0.01L) {
            long double q = theta * theta, term = q / 6, sum = term;
            for (int k = 2; k <= 20; k++) {
                term *= -q / ((2 * k) * (2 * k + 1));
                sum += term;
            }
            return sum;
        }
        return 1 - sinl(theta) / theta;
    }
    int main() {
        ios::sync_with_stdio(false);
        cin.tie(nullptr);
        long double L, n, C;
        cin >> L >> n >> C;
        long double d = n * C;
        if (L == 0 || d == 0) {
            cout << "0.000\n";
            return 0;
        }
        long double target = d / (1 + d), lo = 0, hi = acosl(-1.0L) / 2;
        for (int i = 0; i < 120; i++) {
            long double mid = (lo + hi) / 2;
            if (loss(mid) < target)
                lo = mid;
            else
                hi = mid;
        }
        long double theta = (lo + hi) / 2;
        cout << fixed << setprecision(3) << L / 2 * tanl(theta / 2) << '\n';
    }
    
    • 1

    信息

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