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,那么它也会往同方向 ...
随机推荐
- java并发编程学习:用 Semaphore (信号量)控制并发资源
并发编程这方面以前关注得比较少,恶补一下,推荐一个好的网站:并发编程网 - ifeve.com,上面全是各种大牛原创或编译的并发编程文章. 今天先来学习Semaphore(信号量),字面上看,根本不知 ...
- animate支持的css属性
支持下列CSS 样式 * backgroundPosition * borderWidth * borderBottomWidth * borderLeftWidth * borderRightWid ...
- jquery submit() 提交失败
今天写一个表单提交 居然走到$('#wechat_form').submit() 这,但怎么都没有提交这个表单 google 了一下 Additional Notes:Forms and their ...
- asp.net mvc后台操作之读写xml控制首页动态页面开关显示
一.背景 在asp.net mvc项目里,用户需要开拓几个活动版面,并以侧栏的方式呈现在首页右侧,几个活动时间不一致,为避免浏览者在活动未开放之时进入未开放的服务页面.因此不仅需要在活动代码中加入限制 ...
- 构建自己的 Linux 发行版
如何用 SUSE Studio 构建 Linux 发行版? (1) 进入到 www.susestudio.com,设立一个帐户 (2) 为你的设备(发行版)选择一个基本模板 -软件和软件包选择 (1) ...
- Mac上更新Ruby
因为准备在项目中使用bootstrap,在安装bootstrap过程中提示需要Ruby的版本在1.9.2以上,而目前使用的Ruby版本是Mac系统自带的1.8.7.所以需要对Ruby进行升级.这里使用 ...
- [转] 对称加密算法DES、3DES
转自:http://www.blogjava.net/amigoxie/archive/2014/07/06/415503.html 1.对称加密算法 1.1 定义 对称加密算法是应用较早的加密算法, ...
- [Think In Java]基础拾遗4 - 并发
第21章节 并发 1. 定义任务 任务:任务就是一个执行线程要执行的一段代码.(在C语言中就是函数指针指向的某个地址开始的一段代码) [记忆误区]:任务不是线程,线程是用来执行任务的.即任务由线程驱动 ...
- 【BZOJ-1340】Escape逃跑问题 最小割
1340: [Baltic2007]Escape逃跑问题 Time Limit: 5 Sec Memory Limit: 162 MBSubmit: 264 Solved: 121[Submit] ...
- SpringBoot源码解析:tomcat启动分析
>> spring与tomcat的启动分析:war包形式 tomcat:xml加载规范 1.contex-param: 初始化参数 2.listener-class: contextloa ...