【题目链接】
ybt 1246:膨胀的木棍
OpenJudge NOI 1.11 09:膨胀的木棍
该题数据比较刁钻,只有下面给的第一种写法在两个OJ上都能过。大概理解就行,不用扣为什么我的写法符合逻辑但过不了。
【题目考点】
1. 二分:实数域二分查找
题目要求保留到小数点后m位,在循环时要写为while(r - l >= 1e-(m+1))
比如要求保留到小数点后2位,l和r间的距离要在小于1e-3时才能停止循环。
【解题思路】
解法1:二分求 α \alpha α
根据题目公式
L
′
=
(
1
+
n
∗
C
)
∗
L
L'=(1+n*C)*L
L′=(1+n∗C)∗L求出
L
′
L'
L′
圆心角
∠
A
O
B
的大小
α
\angle AOB 的大小\alpha
∠AOB的大小α最小为0,最大为
π
\pi
π。
二分查找合适的
α
\alpha
α
因为
s
i
n
α
2
=
L
2
r
sin\frac{\alpha}{2} = \frac{L}{2r}
sin2α=2rL
所以
r
=
L
2
s
i
n
α
2
r = \frac{L}{2sin\frac{\alpha}{2}}
r=2sin2αL
求出
A
B
⌢
\overset{\frown}{AB}
AB⌢长为
α
r
=
α
L
2
s
i
n
α
2
\alpha r = \frac{\alpha L}{2sin\frac{\alpha}{2}}
αr=2sin2ααL
比较
α
r
\alpha r
αr与
L
′
L'
L′:
- 如果 α r \alpha r αr比 L ′ L' L′大,那么下一次 α \alpha α要小一点,取左半边区间
- 如果 α r \alpha r αr比 L ′ L' L′小,那么下一次 α \alpha α要大一点,取右半边区间
求出 α \alpha α后,先求 r = L ′ α r = \frac{L'}{\alpha} r=αL′(理论上也可以用 r = L 2 s i n α 2 r = \frac{L}{2sin\frac{\alpha}{2}} r=2sin2αL,但实际使用的话会WA,也许是由于计算太多了导致精度不正确),再求 O P = r ⋅ c o s α 2 OP = r\cdot cos\frac{\alpha}{2} OP=r⋅cos2α,最后 x = r − O P = r − r ⋅ c o s α 2 = r ( 1 − c o s α 2 ) x = r - OP = r-r\cdot cos\frac{\alpha}{2} = r(1-cos\frac{\alpha}{2}) x=r−OP=r−r⋅cos2α=r(1−cos2α)
解法2:二分求x
1. 已知x求 A B ⌢ \overset{\frown}{AB} AB⌢弧长
如图所示,已知线段
A
B
AB
AB长为
L
L
L,
A
B
⌢
\overset{\frown}{AB}
AB⌢长为
L
′
L'
L′,
L
′
L'
L′的长度可以通过题中给的公式求出。
A
B
⌢
\overset{\frown}{AB}
AB⌢所对的圆心角为
α
\alpha
α,线段
M
P
MP
MP长为
x
x
x,也就是要求的木棍中心的偏移距离。该弧的半径是
r
r
r。
P
O
PO
PO长为
r
−
x
r - x
r−x,
A
P
AP
AP为
L
2
\frac{L}{2}
2L,
△
A
P
O
\triangle APO
△APO是直角三角形,根据勾股定理,有:
(
r
−
x
)
2
+
(
L
2
)
2
=
r
2
(r-x)^2+(\frac{L}{2})^2 = r^2
(r−x)2+(2L)2=r2
化简得
r
=
4
x
2
+
L
2
8
x
r = \frac{4x^2+L^2}{8x}
r=8x4x2+L2
求
∠
A
O
P
\angle AOP
∠AOP 的正弦值:
s
i
n
α
2
=
L
2
r
sin\frac{\alpha}{2} = \frac{L}{2r}
sin2α=2rL
所以有:
α
=
2
a
r
c
s
i
n
(
L
2
r
)
\alpha = 2arcsin(\frac{L}{2r})
α=2arcsin(2rL)
所以
A
B
⌢
\overset{\frown}{AB}
AB⌢长度为
α
r
\alpha r
αr
2. x的范围
x最小时为0,此时木棍不膨胀,
L
′
L'
L′ 等于
L
L
L。
x越大,
L
′
L'
L′越大
x最大时近似为r。题目说
L
′
L'
L′最大为L的1.5倍,当该弧为半圆时,
r
=
L
2
r = \frac{L}{2}
r=2L,弧长
为
π
r
=
π
2
L
≈
1.57
L
\pi r = \frac{\pi}{2}L \approx1.57L
πr=2πL≈1.57L,比题目中给定的x最大时的情况要大。
3. 二分求x
通过二分法取x,取到x后根据上面第1点中的方法求出
A
B
⌢
\overset{\frown}{AB}
AB⌢的长度。而后与通过题目给定的膨胀系数公式求出的
L
′
L'
L′进行比较。
如果求出的
A
B
⌢
\overset{\frown}{AB}
AB⌢的长度比
L
′
L'
L′长,说明x取大了,下一次取左半边区间。
如果求出的
A
B
⌢
\overset{\frown}{AB}
AB⌢的长度比
L
′
L'
L′小,说明x取小了,下一次取右半边区间。
【题解代码】
解法1:二分求 α \alpha α
#include <bits/stdc++.h>
using namespace std;
#define PI acos(-1)
double l, c, n, l1;
double getArcAB(double a)
{
return l*a/(2*sin(a/2));
}
int main()
{
cin >> l >> n >>c;
l1 = (1+n*c)*l;
double left = 0, right = PI, mid;
while(right - left >= 1e-12)
{
mid = (left + right) / 2;
if(getArcAB(mid) < l1)
left = mid;
else
right = mid;
}
cout << fixed << setprecision(3) << l1/mid*(1-cos(mid/2));
return 0;
}
if(getArcAB(mid) < l1)
这句,如果写<=
,在OpenJudge上就不过,在ybt上能过。或者最后输出l/(2*sin(mid/2))*(1-cos(mid/2))
,在OpenJudge上能过,在ybt上过不了。这东西没什么道理,就是两个OJ的数据点不同。理解题意的逻辑就行,扣这些细节没意义。
解法2:二分求x
该解法在信息学奥赛一本通OJ上过不了。在OpenJudge上能过。
#include <bits/stdc++.h>
using namespace std;
double l, c, n, l1;
double getArcAB(double x)//通过几何求出的弧长
{
double r, a;
r = (4*x*x+l*l)/(8*x);
a = 2*asin(l/(2*r));
return a*r;
}
int main()
{
cin >> l >> n >>c;
l1 = (1+n*c)*l;
double left = 0, right = l, mid;
while(right - left >= 1e-4)
{
mid = (left + right) / 2;
if(getArcAB(mid) > l1)
right = mid;
else
left = mid;
}
cout << fixed << setprecision(3) << mid;
return 0;
}