Codeforces 598D Igor In the Museum(概率DP)

来源:互联网 发布:ncs刷机软件 编辑:程序博客网 时间:2024/04/27 15:38

@(K ACMer)


题意:
在x轴上有n颗高度为h的树,现在你将有12的概率,砍最左边的树,同样的概率砍最右边的树.然后对于每个树它有p的概率会向左边倒,(1p)的概率会向右边倒.值得注意的是树的倒会引起类似多米诺骨牌效应,也就是如果一个树和它相邻的树和它的距离小于h,它往这颗树倒的时候,该树也会向同样的方向倒.为你这些树全部倒下的期望覆盖地面长度是多少?


分析:
开始很很容易想到一个记忆化搜索的思路,定义dfs(l,r,lf,rf)为当前的最左边界的下标为l最右边界下标为r,最靠近l的覆盖到了lf,最靠近r的覆盖到了rf.这样再分为:1.左边的树向左边倒,2.左边的树向右边倒,3.右边的树向左边倒,4.右边的树向右边倒四种情况来转移就可.
但是写出来记忆优化的时候发现lfrf都太大了,必须需要用map来离散化,所以记忆化的数组是map<pair<int,int>,double>dp[l][r]这样凭空多了个O(logn)的复杂度,既超时间也超内存.
最后发现其实没有必要记录lf,和rf这样大的数只需要记录当前l左边的树是向左倒还是向右倒,当前r右边的树是向左倒还是向右倒,就可以推算出来lfrf.这是有状态dp[l][r][2][2]


code:

#include <iostream>#include <cstdio>#include <cstring>#include <set>#include <map>#include <stack>#include <vector>#include <string>#include <queue>#include <cstdlib>#include <cmath>#include <algorithm>using namespace std;typedef pair<int, int> pii;typedef long long ull;typedef long long ll;typedef vector<int> vi;#define xx first#define yy second#define rep(i, a, n) for (int i = a; i < n; i++)#define sa(n) scanf("%d", &(n))#define vep(c) for(decltype((c).begin()) it = (c).begin(); it != (c).end(); it++)const int mod = int(1e4) + 7, INF = 0x3fffffff, maxn = 1e5 + 12;int n, h, v[2009];double p, eps = 1e-11;double dp[2009][2009][2][2];double dfs(int l, int r, int lf, int rf){    if (l > r) return 0;    int li = l, ri =r;    if (dp[li][ri][lf][rf]) return dp[li][ri][lf][rf];    int lff = l > 0 ? (lf == 0 ? v[l - 1] : v[l - 1] + h ) : -INF;    int rff = r < n - 1 ? (rf == 1 ? v[r + 1] : v[r + 1] - h) : INF;    double ret = 0.0;    ret += p * 0.5 * (min(h, v[l] - lff) + dfs(l + 1, r, 0, rf));    int x = l + 1;    while (x <= r && v[x] < v[x - 1] + h) x++;    x--;    ret += (1 - p) * 0.5 * (min(v[x] - v[l] + h, rff - v[l]) + dfs(x + 1, r, 1, rf));    ret += (1 - p) * 0.5  * (min(h, rff - v[r]) + dfs(l, r - 1, lf, 1));    x = r - 1;    while (x >= l && v[x + 1] < v[x] + h) x--;    x++;    ret += p * 0.5 * (min(v[r] - v[x] + h, v[r] - lff) + dfs(l, x - 1, lf, 0));    return dp[li][ri][lf][rf] = ret + eps;    //return dp[li][ri][make_pair(lf, rf)] = ret + eps;}int main(void){    sa(n), sa(h);    cin >> p;    rep (i, 0, n) sa(v[i]);    sort(v, v + n);    printf("%.15f\n", dfs(0, n - 1, 0, 0));    return 0;}
1 0