Problem Description
给你n个事件,接下来2*n行,给你任何事件可能的开始时间,和任何事件可能的结束时间。
让你输出每个事件存在时间的数学期望
思路:
这道题有两个核心点。
一:算期望的时候,事件时间差 两两相减的话,O(n*n)会超时。我们需要对公式进行处理。我们拿例子来说明把。
例如样例
3
+ 4
+ 10
- 11
+ 16
- 20
- 100
对于4这个事件存在时间的期望 = (11-4) * 0.5 + (20-4) * 0.25 + (100 - 4) * 0.25 = 11 * 0.5 + 20 * 0.25 + 100 * 0.25 - 4 * (0.5 + 0.25 + 0.25)。因为对于一个事件,概率和等于1。所以式子等于 11 * 0.5 + 20 * 0.25 + 100 * 0.25 - 4
二: 如何处理对于每个事件的 结束时间的期望也就是这个式子11 * 0.5 + 20 * 0.25 + 100 * 0.25。对于事件4这个式子其实是 11*0.5 + 20*0.5*0.5 + 100*0.5*0.5*1 对于事件16这个式子就变成了20*0.5 + 100*0.5
正着求,有点小复杂(我一开始就是正着,没能敲出来,看了学长的代码发现倒着贼方便),倒着求,详细看代码
#include<bits/stdc++.h>
using namespace std;
#define maxn 200008
int t[maxn], Count[maxn];
int vis[maxn];
double ans[maxn];
int main()
{
int n, i;
char s[10];
while(~scanf("%d", &n))
{
memset(Count, 0, sizeof(Count));//记录到这个i点,有多少正在开始的事件
memset(vis, 0, sizeof(vis));
for(i = 1; i <= 2*n; i++)
{
scanf("%s %d", s, &t[i]);
if(s[0] == '+') {
vis[i] = 1;
Count[i] = Count[i-1] + 1;
}
else Count[i] = Count[i-1] - 1;
}
double sum = 0;
int k;
for(i = 2*n; i >= 1; i--)//倒着求ans[]数组,也就是上面强调的式子
{
if(!vis[i])
{
k = Count[i] + 1;
sum = sum*(1-1.0/k) + 1.0*t[i]/k;
}
else
{
ans[i] = sum;
}
}
for(i = 1; i <= 2*n; i++)
{
if(vis[i])
printf("%.10lf\n", ans[i] - t[i]);
}
}
return 0;
}