cf596d
题意:有一排等高的树木,高度都为h。给出每棵树在数轴上的坐标,每次有可能是最左边或者最右边的立着的树倒下,概率都是0.5。最终所有树都倒下。每棵树在倒下的时候有p的概率向左倒,1-p的概率向右倒。如果某些树之间的距离小于h,那么倒下的时候可能产生连带效应。问最后所有树都倒下时,在数轴上覆盖的线段的总长度是多少。
分析:
概率DP求期望:
我们以前学过的求期望的方法是每种结果出现的概率乘以每种结果的值,然后相加。但是通常解决这类问题我们都要对每个中间状态求期望值,最终算出总的期望。这时我们就可以把每个状态的后继状态(子问题)看成是一个结果值,而不是期望值。
如果是算期望通常需要逆向思维E(u)=sigma(pv*E(v)+C),其中C是状态u和状态v之间的期望差值,pv是u状态转移到v状态的概率。v是u拆分后的子问题。
注意:sigma(pv)=1
本题我们开一个数组叫f[l][r][a][b]。
表示现在从l到r的树还立着,a=0表示l-1树向左倒的,a=1表示其向右倒的。b同理描述了r+1树的倒法。
我们下面来看它的一个后继状态,l向左倒。
f[l][r][a][b]+= 0.5 * p * (f[l+1][r][0][b] + l向左倒下时覆盖长度的增量)。
注意处理一些特殊情况,例如连带倒下,有可能需要将l+1换成right_most[l]表示最远能倒到哪棵。覆盖长度增量也要注意处理一次性所有树都倒下了的情况。
其他状态转移的话用同样方法再加上l向右,r向左向右倒的状态就行了。
#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std; #define d(x) const int INF = 0x3f3f3f3f;
const int MAX_N = ; int n, h;
double p;
int pos[MAX_N];
double f[MAX_N][MAX_N][][];
int left_most[MAX_N];
int right_most[MAX_N]; void input()
{
scanf("%d%d%lf", &n, &h, &p);
for (int i = ; i < n; i++)
{
scanf("%d", &pos[i]);
}
} int get_pos(int a)
{
if (a < )
return -INF;
if (a >= n)
return INF;
return pos[a];
} int get_dist(int a, int b)
{
return get_pos(b) - get_pos(a);
} int get_increment_left(int i, int a)
{
return min(h, get_dist(i - , i) - h * a);
} int get_increment_right(int i, int b)
{
return min(h, get_dist(i, i + ) - h * ( - b));
} double cal(int l, int r, int a, int b)
{
double ret = ;
int temp1 = ;
int temp2 = ;
int temp = ; ret += 0.5 * p * (get_increment_left(l, a) + f[l + ][r][][b]); ret += 0.5 * ( - p) * (get_increment_right(r, b) + f[l][r - ][a][]); temp1 = get_dist(l, right_most[l]) + h;
temp2 = get_dist(l, r + ) - ( - b) * h;
temp = min(temp1, temp2);
ret += 0.5 * ( - p) * (temp + f[right_most[l] + ][r][][b]); temp1 = get_dist(left_most[r], r) + h;
temp2 = get_dist(l - , r) - a * h;
temp = min(temp1, temp2);
ret += 0.5 * p * (temp + f[l][left_most[r] - ][a][]); return ret;
} void cal(int l, int r)
{
for (int a = ; a < ; a++)
{
for (int b = ; b < ; b++)
{
if (a == && get_dist(l - , l) < h)
continue;
if (b == && get_dist(r, r + ) < h)
continue;
f[l][r][a][b] = cal(l, r, a, b);
d(printf("f[%d][%d][%d][%d]=%.3f\n", l, r, a, b, f[l][r][a][b]));
}
}
} double work()
{
memset(f, , sizeof(f));
for (int i = ; i < n; i++)
{
for (int a = ; a < ; a++)
{
for (int b = ; b < ; b++)
{
if (a == && get_dist(i - , i) < h)
continue;
if (b == && get_dist(i, i + ) < h)
continue;
//the value of a and b: 0 left, 1 right
f[i][i][a][b] = p * get_increment_left(i, a);
f[i][i][a][b] += ( - p) * get_increment_right(i, b);
d(printf("f[%d][%d][%d][%d]=%.3f\n", i, i, a, b, f[i][i][a][b]));
}
}
} for (int len = ; len < n; len++)
{
for (int i = ; i + len < n; i++)
{
int l = i;
int r = i + len;
cal(l, r);
}
}
return f[][n - ][][];
} void make()
{
for (int i = ; i < n; i++)
{
if (get_dist(i - , i) < h)
left_most[i] = left_most[i - ];
else
left_most[i] = i;
}
for (int i = n - ; i >= ; i--)
{
if (get_dist(i, i + ) < h)
right_most[i] = right_most[i + ];
else
right_most[i] = i;
}
} int main()
{
input();
sort(pos, pos + n);
make();
printf("%.9f\n", work());
return ;
}
cf596d的更多相关文章
- CF596D Wilbur and Trees
题意:有一些高度为h的树在数轴上.每次选择剩下的树中最左边或是最右边的树推倒(各50%概率),往左倒有p的概率,往右倒1-p. 一棵树倒了,如果挨到的另一棵树与该数的距离严格小于h,那么它也会往同方向 ...
随机推荐
- 学习C++.Primer.Plus 10 对象和类
1.类的声明和定义 类的声明和定义. 类声明的格式如下: class className { private://private 是类对象的默认访问控制,因此,可以省略 data member del ...
- 在CSS中定义a:link、a:visited、a:hover、a:active顺序
摘自:http://blog.snsgou.com/post-2.html 以前用CSS一直没有遇到过这个问题,在最近给一个本科同学做的项目里面.出现一些问题,搜索引擎查了一些网站和资料,发现 ...
- css的命名规则
本文转载自谈笑涧<css的命名规则> 操作系统版本:Windows 7 浏览器版本:IE6,IE7,IE8,Firefox 3.6.2,Safari 4.0.4,Chrome 5.0.35 ...
- Promiscuous Mode
简介 Monitor mode 与 promiscuous mode 比较 这是在网卡上的的两个特殊的模式,简而言之,都是将网卡的过滤器关闭. Monitor mode 这是我们常常提到的snif ...
- 详解 Android Activity 生命周期
从以下几个方面详细说一下Activity的生命周期: 1.回到主屏幕再打开和退出程序的时候. 2.屏幕旋转的时候. 3.打开其它的Activity的情况. 4.打开一个Layou透明的Activity ...
- C 语言学习 第五次作业总结
第五次作业,主要学习和复习的是几种循环结构的使用. 在前一次的课堂上,同学们已经学习了分支语句的使用.分支语句和循环语句配合使用,就可以写出更多的,逻辑功能丰富的代码了. 逻辑功能的丰富,也意味着学习 ...
- C 语言学习 第二次作业总结
本次作业内容,主要有以下几点: 新建 coding 帐号,且使用 coding 上传本次作业的代码 Printf及条件判断语句的使用 作业总结 作业总结: 同学们开始渐入佳境,能够较为流畅的写出合理的 ...
- Chrome-Console( Command Line API Reference)
来源于:https://developers.google.com/web/tools/chrome-devtools/console/command-line-reference The Comma ...
- MySQL主从复制中常见的3个错误及填坑方案
一.问题描述 主从复制错误一直是MySQL DBA一直填不完的坑,如鲠在喉,也有人说mysql主从复制不稳定云云,其实MySQL复制比我们想象中要坚强得多,而绝大部分DBA却认为只要跳过错误继续复制就 ...
- TWRP基于omnirom 6.0.1编译教程
1.环境搭配 参照CM13.0编译笔记http://www.cnblogs.com/dinphy/p/5670293.html 参照SM 2.0 编译笔记http://www.cnblogs.com/ ...