膨胀的木棍

GitHub跳转原题关系图返回列表

弧长与弦长固定时圆心角唯一,二分求角后代弓形高公式输出偏移。

OJ: roj

题目 ID: 1246

难度:普及-

标签:数学二分计算几何python

创建: 2026-09-30 01:32

更新: 2026-10-07 12:15

题目描述

木棍原长 LL,温度变化 nn,热膨胀系数 CC。受热后长度变为 L′=(1+nC)LL'=(1+nC)L(保证 L′≤1.5LL'\le 1.5L),木棍弯成圆弧,弦仍为原位置线段(长 LL)。输出弧中点到弦的垂直距离,保留三位小数。

输入:三个非负实数 L,n,CL,n,C。输出:木棍中心偏移距离。

样例输入:1000 100 0.0001,样例输出:61.329。

思路

由 r=L′/θr=L'/\theta 与弦长公式 L=2rsin⁡(θ/2)L=2r\sin(\theta/2) 消去半径,得方程 2L′sin⁡(θ/2)/θ=L2L'\sin(\theta/2)/\theta=L。左端在 (0,π](0,\pi] 严格递减,实数二分求圆心角 θ\theta,再代回 h=r(1−cos⁡(θ/2))h=r(1-\cos(\theta/2)) 输出弓形高。

参考代码

Python 版:

python
#!/usr/bin/env python3
# Author by Rainboy blog: https://rainboylv.com github: https://github.com/rainboylvx
# rbook: -> https://rbook.roj.ac.cn  https://rbook2.roj.ac.cn
# rainboy的学习导航网站: https://idx.roj.ac.cn
# create_at: 2026-09-30 01:33
# update_at: 2026-09-30 01:38

import sys
from math import sin, cos

EPS = 1e-12  # 二分终止精度:角度差小于它就不再细分(与 std.cpp 的 E 一致)


def solve() -> None:
    data = iter(map(float, sys.stdin.buffer.read().split()))
    length, n, c = next(data), next(data), next(data)  # 原长、温度变化、热膨胀系数
    expanded = (1 + n * c) * length  # 受热后的弧长 L'

    # 圆心角 θ 唯一:半径 r = L'/θ,弦长 2r·sin(θ/2),要求弦长恰等于原长 L。
    # 弦长关于 θ 严格递减(θ→0 时弦→弧长 L',θ=π 时弦=2L'/π 的最小值),可二分。
    lo, hi = 0.0, 3.15  # 上界取略大于 π 即可覆盖弧长 ≤ 1.5L 的全部情形
    while hi - lo > EPS:
        mid = (lo + hi) / 2
        chord_too_long = 2 * expanded * sin(mid / 2) / mid > length  # 该角度下的弦长
        if chord_too_long:
            lo = mid  # 弦偏长说明还不够弯,角度要变大
        else:
            hi = mid

    # 中心偏移 = 弓形高 = r - r·cos(θ/2),其中 r = L' / θ
    radius = expanded / hi
    print(f"{radius * (1 - cos(hi / 2)):.3f}")


if __name__ == "__main__":
    solve()

C++ 版(同一算法):

cpp
/**
 * Author by Rainboy blog: https://rainboylv.com github: https://github.com/rainboylvx
 * rbook: -> https://rbook.roj.ac.cn  https://rbook2.roj.ac.cn
 * rainboy的学习导航网站: https://idx.roj.ac.cn
 * create_at: 2026-10-05 06:54
 * update_at: 2026-10-05 06:54
 */
#include <bits/stdc++.h>
using namespace std;

typedef long long ll;

const double EPS = 1e-12; // 二分终止精度,远超三位小数输出要求

double L, n, C;  // 木棍原长、温度变化、热膨胀系数

// 输入为一个浮点数序列,直接读入即可。
void read_input() {
    cin >> L >> n >> C;
}

// 核心:弧长 L' = (1+n*C)*L 固定,弦长 = L 固定,圆心角 θ 唯一。
// 由 r = L'/θ 与 L = 2*r*sin(θ/2) 消去 r,得到方程 2*L'*sin(θ/2)/θ = L。
// 左端在 (0,π] 严格递减,且 g(0+) = L' ≥ L,g(π) < L,故可二分 θ。
void solve() {
    double expanded = (1.0 + n * C) * L; // 受热后的弧长 L'

    double lo = 0.0, hi = 3.15; // 上界略大于 π 即可
    while (hi - lo > EPS) {
        double mid = (lo + hi) / 2.0;
        double chord = 2.0 * expanded * sin(mid / 2.0) / mid; // 当前 θ 对应的弦长
        if (chord > L) {
            lo = mid; // 弦偏长 => 还不够弯 => 角度调大
        } else {
            hi = mid; // 弦偏短/相等 => 角度调小
        }
    }

    double theta = hi;            // 最终圆心角
    double radius = expanded / theta; // 半径 r = L'/θ
    double h = radius * (1.0 - cos(theta / 2.0)); // 弓形高 = r - r*cos(θ/2)

    cout << fixed << setprecision(3) << h << "\n";
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    read_input();
    solve();

    return 0;
}