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,那么它也会往同方向 ...
随机推荐
- 再谈Newtonsoft.Json高级用法
上一篇Newtonsoft.Json高级用法发布以后收到挺多回复的,本篇将分享几点挺有用的知识点和最近项目中用到的一个新点进行说明,做为对上篇文章的补充. 阅读目录 动态改变属性序列化名称 枚举值序列 ...
- 利用 lucene.net 实现高效率的 WildcardQuery ,记一次类似百度搜索下拉关键字联想功能的实现。
打开百度输入 站内搜索也要实现类似功能.最基础的做法,写个方法查数据库搜索历史综合表keywordSearch(先将被搜索过的关键字记录到一张表,记录好他们被搜索的次数.上次搜索的有多少结果) 大概 ...
- 如何用PowerShell列出你机器上的.NET Framework的版本号和SP服务补丁
代码下载:本文提到的脚本,可以从微软的代码库下载, How to determine versions & service pack levels of .NET Framework by P ...
- 第一章,阿里的Dubbo完美初级搭建,待续。。。
1.1 后台工程搭建分析 Web工程. Maven的常见打包方式:jar.war.pom Pom工程一般都是父工程,管理jar包的版本.maven插件的版本.统一的依赖管理.聚合工程. Taotao- ...
- 极光推送JPush的快速集成
首先到极光推送的官网上创建一个应用,填写对应的应用名和包名. 创建好之后下载Demo 提取Sdk里面的图片和xml等资源文件放自己项目的相应位置,然后要注意的是.so文件的放置位置: 在main目录下 ...
- 【转】error LNK2019: 无法解析的外部符号 "__declspec(dllimport)
生成DLL文件的字符集是Unicode而生成exe文件的字符集为默认的ASCII. 只要统一字符集即可解决问题: VS2005的c++项目默认字符集是使用 Unicode 字符集,在项目属性-> ...
- html中的rel,rev是什么?
html中的rel,rev是什么? 这2个标记主要是用于表示文档之间的联系,rel是从源文档到目标文档的关系:rev是从目标文档到源文档的关系 经常用到的属性如下: Alternate - 定义交替出 ...
- jquery版的全选,全不选和反选
<!DOCTYPE html><html> <head> <meta charset="UTF-8"> <script src ...
- logging 模块误用导致的内存泄露
首先介绍下怎么发现的吧, 线上的项目日志是通过 logging 模块打到 syslog 里, 跑了一段时间后发现 syslog 的 UDP 连接超过了 8W, 没错是 8 W. 主要是 logging ...
- TypedReference
http://stackoverflow.com/questions/4764573/why-is-typedreference-behind-the-scenes-its-so-fast-and-s ...