您的位置:首页 > 其它

「2016山东省队集训」 LYK loves jumping

2017-01-05 08:53 549 查看

题目描述

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的值还改了。。。

代码

#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);
}


4000
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: