题意:有一排等高的树木,高度都为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的更多相关文章

  1. CF596D Wilbur and Trees

    题意:有一些高度为h的树在数轴上.每次选择剩下的树中最左边或是最右边的树推倒(各50%概率),往左倒有p的概率,往右倒1-p. 一棵树倒了,如果挨到的另一棵树与该数的距离严格小于h,那么它也会往同方向 ...

随机推荐

  1. 再读《C++ Primer》——变量和基本类型

    刚上大学那时,几个室友一块买了本<C++ Primer>第4版,看了一遍后就没怎么碰了,偶尔拿出来翻翻,当作工具书使用.后来知道有第5版了,一直觉得内容差不多吧.直到最近,再读其中的一些内 ...

  2. jQuery EasyUI视频教程合集

    下载地址:http://www.fu83.cn/thread-269-1-1.html 教程内容: 尚学堂科技_jqueryeasyui视频教程_白贺翔 李炎恢jQuery EasyUI视频教程全集 ...

  3. linux 代码分析工具 gprof - 以wpa_supplicant为例

        当我们遇到一个新的程序的时候,经常会无从下手,需要debug一个功能的时候,我们不知道函数的运行流程是怎么样的,这就需要借助工具来帮助我们加快流程了.这里以分析wpa_supplicant为例 ...

  4. Mongodb学习笔记四(Mongodb聚合函数)

    第四章 Mongodb聚合函数 插入 测试数据 ;j<;j++){ for(var i=1;i<3;i++){ var person={ Name:"jack"+i, ...

  5. 【跟着子迟品 underscore】Array Functions 相关源码拾遗 & 小结

    Why underscore 最近开始看 underscore.js 源码,并将 underscore.js 源码解读 放在了我的 2016 计划中. 阅读一些著名框架类库的源码,就好像和一个个大师对 ...

  6. C#基础系列——小话泛型

    前言:前面两章介绍了C#的两个常用技术:C#基础系列——反射笔记 和 C#基础系列——Attribute特性使用 .这一章来总结下C#泛型技术的使用.据博主的使用经历,觉得泛型也是为了重用而生的,并且 ...

  7. git远程仓库

    git远程仓库: 目前我们使用到的 Git 命令都是在本地执行,如果你想通过 Git 分享你的代码或者与其他开发人员合作. 你就需要将数据放到一台其他开发人员能够连接的服务器上. 添加远程仓库: gi ...

  8. 【原创】cs+html+js+css模式(七): 顺序执行与并发执行问题,IIS7及其以上版本的抛错问题解决

          在进行开发的过程中,针对于这种模式,我们继承的IRequiresSessionState,这种对于我们的同一个IIS的执行中是顺序执行即一个ajax请求处理完成后,才能执行下一个ajax, ...

  9. tomcat设置虚拟目录开启文件下载在服务

    因为平时一直在eclipse里运行tomcat,所以改的文件在eclipse里的server 在server.xml里找到<host></host>,并在</host&g ...

  10. <<< PermGen space溢出解决方法

    错误信息中的PermGen space的全称是Permanent Generation space,是指内存的永久保存区域.还没有弄明白PermGen space是属于非堆内存,还是就是非堆内存,但至 ...