没有提交地址
题目描述
LYK 发现了 n 个点,它想在这些点上跳来跳去。
具体地,第 i 个点有一个高度
hi
,当 LYK 踩在这个点上方时,这个点会下降
ti
,也就是说此时该点高度为
hi−ti
,当 LYK 离开该点时,这个点又会恢复到原来的
hi
。
现在 LYK 每次可以跳到不超过它当前所在点高度的点(当
ti
=0 时,LYK 可以跳到自己所在的点) ,若存在多个这样的点,则 LYK 等概率随机挑选一个点并跳到那个点,若不存在这样的点,则 LYK 会跳到地面。
求 LYK 以第 i 个点为起点时,期望跳几次能够跳到地面(保留 3 位有效数字) 。
若期望步数为无穷,输出 0.000。
设
∞
表示无穷大,X 为一个数,有
∞
-X=
∞
,
∞
*X=
∞
,
∞
/X=
∞
,
∞
+X=
∞
。
输入格式
第一行输入一个数 n,表示有 n 个点。 第二行输入 n 个数,表示 hi 。 第三行输入 n 个数,表示 ti 。
输出格式
输出一行 n 个数,表示以当前点为起点时,期望跳几次跳到地面(保留 4 位小数) ,若期望次数为无穷,输出“0.000” 。
样例输入
4
4 2 2 3
0 1 0 0
样例输出
3.8333 1.0000 3.0000 3.5000
数据范围
对于 20%的数据
n≤5
。
对于另外 20%的数据所有
hi
都相等。
对于再另外 20%的数据不存在
ti
=0。
对于再再另外 20%的数据
hi
都互不相等。
对于 100%的数据
1≤n,hi≤105
,
0≤ti≤hi
。
思路:
首先按高度的升序排序,把
ti=0
且
hi
相同的提取出来另算,每次二分找出可以跳的区间,记录答案。
设
dp[i]
表示
i
跳出去的期望,每次转移时,可以跳的有
当
- 当 a=0 时: dp[i]=1
- 否则: dp[i]=∑aj=1dp[j]a+1
当 ti=0 时:
- 当 a−b=0 时: dp[i]=−inf
- 否则: dp[i]=∑a−bj=1dp[j]a−b+aa−b
代码:
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cmath>
using namespace std;
const double eps = 0.00000001;
const double inf = 1e12;
struct node{
int h, t, b, pos;
double res;
bool operator < (const node &tt)const{
return h == tt.h ? (t > tt.t) : (h < tt.h);
}
void operator = (const node &tt){
h = tt.h;
t = tt.t;
b = tt.b;
pos = tt.pos;
res = tt.res;
}
};
bool cmp(node a, node b){
return a.pos < b.pos;
}
node p0[100010], p[100010];
double dp[100010], sum2[100010];
int sum1[100010], n, cnt;
int find(int l, int r, int val){
int res = 0;
while(l <= r){
int mid = (l+r)>>1;
if(p[mid].h <= val) res = mid, l = mid + 1;
else r = mid - 1;
}
return res;
}
int main(){
scanf("%d", &n);
for(int i = 1; i <= n; i ++) scanf("%d", &p0[i].h);
for(int i = 1; i <= n; i ++) scanf("%d", &p0[i].t), p0[i].pos = i;
sort(p0+1, p0+1+n);
for(int i = 1; i <= n; i ++){
if(p0[i].h == p0[i-1].h && p0[i].t == p0[i-1].t) p[cnt].b ++;
else p[++cnt] = p0[i], p[cnt].b = 1;
}
for(int i = 1; i <= cnt; i ++){
sum1[i] = sum1[i-1] + p[i].b;
int pos = find(1, i, p[i].h-p[i].t);
double a = sum1[pos];
if(p[i].t != 0){
if(a == 0) p[i].res = 1;
else p[i].res = (sum2[pos]/a)+1;
}else{
if(a-p[i].b == 0) p[i].res = -inf;
else p[i].res = (sum2[pos-1]/(a-p[i].b))+(a/(a-p[i].b));
}
sum2[i] = p[i].b*p[i].res + sum2[i-1];
}
for(int i = 1, pp = 0; i <= n; i ++){
if(p0[i].h == p0[i-1].h && p0[i].t == p0[i-1].t) ;
else pp ++;
p0[i].res = p[pp].res;
}
sort(p0+1, p0+1+n, cmp);
for(int i = 1; i <= n; i ++) printf("%.3lf ", p0[i].res <= 0 ? (0.000) : (p0[i].res));
return 0;
}