题目描述
LYK 发现了 n 个点,它想在这些点上跳来跳去。
具体地,第 i 个点有一个高度 hi,当 LYK 踩在这个点上方时,这个点会下降 ti,也就是说此时该点高度为 hi-ti,当 LYK 离开该点时,这个点又会恢复到原来的 hi。
现在 LYK 每次可以跳到不超过它当前所在点高度的点(当 ti=0 时,LYK 可以跳到自己所在的点) ,若存在多个这样的点,则 LYK 等概率随机挑选一个点并跳到那个点,若不存在这样的点,则 LYK 会跳到地面。
求 LYK 以第 i 个点为起点时,期望跳几次能够跳到地面(保留 3 位有效数字) 。
若期望步数为无穷,输出 0.000。
设 oo 表示无穷大,X 为一个数,有 oo-X=oo,oo*X=oo,oo/X=oo,oo+X=oo。
输入格式(jumping.in)
第一行输入一个数 n,表示有 n 个点。
第二行输入 n 个数,表示 hi。
第三行输入 n 个数,表示 ti。
输出格式(jumping.out)
输出一行 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<=10^5,0<=ti<=hi。
题解
算法一:
高斯消元,只需要列出所有的方程,跑高斯消元即可。
算法二:
因为hi都相等,因此如果ti≠0,那么这个点肯定是终止点,否则一定可以走下去。
因此我们只需要列个方程,直接解出来即可。
算法三:
不存在ti=0,意思就是肯定不存在环。拓扑图上维护下前缀和,直接裸的DP即可。
算法四:
Ans_i=Ans_i*cnt/tot+sum/tot+1,cnt为和当前点h一样t是0的点的个数(若当前点t不为0,则cnt=0),tot是当前点能走到的点的个数,sum是当前点能走到的点的答案和。然后化简一下,得到Ans_i=(sum+tot)/(tot-cnt),于是我们先按照h升序排序,再按照t降序排序,用个树状数组维护一下前缀和(sum),然后计算答案即可。复杂度O(NlogN)。
题外话,蒟蒻写cmp的时候一开始>写成了>=于是不知为啥re、wa。。。跑完一遍n的值还改了。。。
代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
| #include <cstdio>
#include <algorithm>
using namespace std;
struct Data {
int h, t, id;
double ans;
} a[100005];
int n, maxh = -1;
const double INF = 1.0 / 0.0;
double c[100005];
bool cmpht(Data x, Data y) {
return x.h < y.h || (x.h == y.h && x.t > y.t);
}
bool cmpid(Data x, Data y) {
return x.id < y.id;
}
void change(int pos, double val) {
for (int i = pos; i <= maxh; i += i & -i) c[i] += val;
}
double query(int pos) {
double ret = 0;
for (int i = pos; i; i -= i & -i) ret += c[i];
return ret;
}
int cnt[100005];
int main() {
scanf("%d", &n);
for (int i = 1; i <= n; ++i) {
scanf("%d", &a[i].h);
cnt[a[i].h] ++;
maxh = max(maxh, a[i].h);
}
for (int i = 1; i <= maxh; ++i)
cnt[i] += cnt[i - 1];
for (int i = 1; i <= n; ++i)
scanf("%d", &a[i].t);
for (int i = 1; i <= n; ++i)
a[i].id = i;
sort(a+1,a+n+1,cmpht);
int nowh = 1; double Ans;
for (int i = 1; i <= n;) {
if (a[i].t == 0) {
int j; for (j = i + 1; a[i].h == a[j].h && a[j].t == 0 && j <= n; ++j); --j;
if (cnt[a[i].h] == 0) Ans = 1;
else Ans = (query(a[i].h - a[i].t) + cnt[a[i].h]) / (cnt[a[i].h] - (j - i + 1));
for (int k = i; k <= j; ++k)
a[k].ans = Ans;
change(a[i].h, Ans * (j - i + 1));
i = j + 1;
} else {
if (cnt[a[i].h - a[i].t] == 0) Ans = 1;
else Ans = (query(a[i].h - a[i].t) + cnt[a[i].h - a[i].t]) / (cnt[a[i].h - a[i].t]);
a[i].ans = Ans;
change(a[i].h, Ans);
++i;
}
}
sort(a+1, a+1+n, cmpid);
for (int i = 1; i <= n; ++i)
if (a[i].ans == INF)
a[i].ans = 0;
for (int i = 1; i <= n; ++i)
printf("%.4lf ", a[i].ans);
}
|