UVA-11722 Joining with Friend
题目链接
题目大意
给定一个整数 w w w和两个闭区间 [ t 1 , t 2 ] [t_1, t_2] [t1,t2], [ s 1 , s 2 ] [s_1,s_2] [s1,s2], t 0 , s 0 t_0, s_0 t0,s0分别是这两个闭区间里的两个随机数,求 ∣ t 0 − s 0 ∣ ≤ w |t_0-s_0| \leq w ∣t0−s0∣≤w的概率。
解题思路
思路1(应该不是正解)
首先这肯定是一道数学题
(首先定义
l
e
n
(
[
a
,
b
]
)
=
b
−
a
len([a, b]) = b-a
len([a,b])=b−a)
在数学上一种很有用的方法叫做消元,因此先考虑
t
0
t_0
t0一定的情况,显然的是,如果
t
0
t_0
t0一定,答案应该是
P
(
t
=
t
0
)
=
l
e
n
(
[
t
0
−
w
,
t
0
+
w
]
∩
[
s
1
,
s
2
]
)
l
e
n
(
[
s
1
,
s
2
]
)
P(t = t_0) = \frac{len([t_0-w,t_0+w] \cap [s_1, s_2])}{len([s_1,s_2])}
P(t=t0)=len([s1,s2])len([t0−w,t0+w]∩[s1,s2]),这当然是极易求值的。但是呢,这道题
t
0
t_0
t0在
[
t
1
,
t
2
]
[t_1,t_2]
[t1,t2]中变化,因此我们要求的答案应该是
P
ˉ
(
t
=
t
0
)
\bar{P}(t = t_0)
Pˉ(t=t0)其中
t
0
∈
[
t
1
,
t
2
]
t_0 \in [t_1,t_2]
t0∈[t1,t2](即在闭区间
[
t
1
,
t
2
]
[t_1,t_2]
[t1,t2]上
P
P
P的平均值)。但是由于
t
0
∈
R
t_0 \in R
t0∈R,有无限个,我们不能通过常规方式求和,这里自然想到积分。于是:
a
n
s
=
∫
t
1
t
2
P
(
t
=
t
0
)
d
t
0
l
e
n
(
[
t
1
,
t
2
]
)
ans = \frac{\displaystyle\int^{t_2}_{t_1}P(t=t_0)dt_0}{\displaystyle len([t_1,t_2])}
ans=len([t1,t2])∫t1t2P(t=t0)dt0
怎么求积分呢,通过观察
P
(
t
=
t
0
)
P(t=t_0)
P(t=t0)可知,这个函数的图像是分段的,但是每一段都是直线,而且分段点都只能是整数,因此,对于计算机而言,穷举闭区间
[
t
1
,
t
2
]
[t_1,t_2]
[t1,t2]上所有相邻整数的中间点再求和便是结果,即:
a
n
s
=
∑
t
0
=
t
1
t
2
−
1
P
(
t
=
t
0
+
(
t
0
+
1
)
2
)
t
2
−
t
1
ans = \frac{\displaystyle \sum^{t_2-1}_{t_0=t1}P(t=\frac{t_0+(t_0+1)}{2})}{\displaystyle t_2 - t_1}
ans=t2−t1t0=t1∑t2−1P(t=2t0+(t0+1))
那么代码如下:
#include<cmath>
#include<cstdio>
using namespace std;
#define ffopen(name) freopen(name".in", "r", stdin); freopen(name".out", "w", stdout)
int t1, t2, s1, s2, w;
inline double P(double t0){
double g1, g2;
g1 = t0 - w;
g2 = t0 + w;
if(g2 < s1) return 0.0;
if(g1 > s2) return 0.0;
return (fmin(s2, g2) - fmax(s1, g1)) / (s2 - s1);
}
int main(){
ffopen("testdata");
int T;
scanf("%d", &T);
for(int tn = 1; tn <= T; tn++){
scanf("%d%d%d%d%d", &t1, &t2, &s1, &s2, &w);
double ans = 0;
for(int t0 = t1; t0 < t2; t0++){
ans += P(t0 + 0.5);
}
ans /= (t2 - t1);
printf("Case #%d: %.8f\n", tn, ans);
}
return 0;
}
思路2(这个应该是正解)
我们既然已经想到了定义区间的长度,而这个题有两个区间,自然的,长度乘长度就是面积了,因此这个题的正解应该是线性规划(毕竟积分太难了)。
那么这里,任意一对满足
t
0
∈
[
t
1
,
t
2
]
,
s
0
∈
[
s
1
,
s
2
]
t_0 \in [t_1,t_2],s_0 \in [s_1,s_2]
t0∈[t1,t2],s0∈[s1,s2]的实数对
(
t
0
,
s
0
)
(t_0,s_0)
(t0,s0)便是可能发生的一种情况。
所以,
l
e
n
(
[
t
1
,
t
2
]
)
×
l
e
n
(
[
s
1
,
s
2
]
)
len([t_1,t_2]) \times len([s_1,s_2])
len([t1,t2])×len([s1,s2])就应该为总可能性,这是一个矩形的面积,而满足要求的解应该是位于
t
0
−
s
0
=
w
t_0-s_0=w
t0−s0=w和
s
0
−
t
0
=
w
s_0-t_0 = w
s0−t0=w两条直线之间,裸的线性规划问题,求直线与矩形的交点再分情况讨论就好。
代码如下:
#include<cmath>
#include<cstdio>
using namespace std;
#define ffopen(name) freopen(name".in", "r", stdin); freopen(name".ans", "w", stdout)
int t1, t2, s1, s2, w;
long double S, S1, S2;
int sw1, sw2, tw1, tw2;
int main(){
ffopen("testdata");
int T;
scanf("%d", &T);
for(int tn = 1; tn <= T; tn++){
scanf("%d%d%d%d%d", &t1, &t2, &s1, &s2, &w);
S = (t2 - t1) * (s2 - s1);
sw1 = t1 + w; sw2 = t2 + w;
tw1 = s1 - w; tw2 = s2 - w;
if(sw1 > s2){
S1 = 0.0L;
}else if(sw1 < s1){
if(sw2 > s2) S1 = 0.5L * (tw1 - t1 + tw2 - t1) * (s2 - s1);
else if(sw2 < s1) S1 = S;
else S1 = S - 0.5L * (t2 - tw1) * (sw2 - s1);
}else{
if(sw2 > s2) S1 = 0.5L * (s2 - sw1) * (tw2 - t1);
else S1 = 0.5L * (s2 - sw1 + s2 - sw2) * (t2 - t1);
}
sw1 = t1 - w; sw2 = t2 - w;
tw1 = s1 + w; tw2 = s2 + w;
if(sw1 > s2){
S2 = 0.0L;
}else if(sw1 < s1){
if(sw2 > s2) S2 = 0.5L * (tw1 - t1 + tw2 - t1) * (s2 - s1);
else if(sw2 < s1) S2 = S;
else S2 = S - 0.5L * (t2 - tw1) * (sw2 - s1);
}else{
if(sw2 > s2) S2 = 0.5L * (s2 - sw1) * (tw2 - t1);
else S2 = 0.5L * (s2 - sw1 + s2 - sw2) * (t2 - t1);
}
printf("Case #%d: %.8Lf\n", tn, (S2 - S1) / S);
}
return 0;
}

浙公网安备 33010602011771号