http://codeforces.com/contest/596/problem/D
题目大意:
有n棵树排成一排,高度都为h.
主人公要去砍树,每次等概率地随机选择没倒的树中最左边的树或者最右边的树把它砍倒.每棵树被砍到后,有p的概率会往左边倒,(1-p)的概率往右边倒.
树倒下后如果压到别的树,即如果那棵树倒下的方向上距离不到h的地方还有一棵树,,那么那棵树也会朝和这个树相同的方向倒下.
问最后所有的树都被砍完后覆盖的地面的长度的期望.
思路:dp[i][j][0/1][0/1]代表i到j这个区间,i-1的状态是0/1,j+1的状态是0/1的长度期望
我们每次只求当前倒下树增加的期望.
转移比较复杂:
当l=r时,判断有没有被左右某棵树压倒,有那就直接取这样做的贡献
否则我们要算上概率,p往左倒,1-p往右倒
当l不等于r时,我们有最左边和最右边的两棵树的选择,同样看一下有没有被外层的某棵树压倒,压倒就直接算,否则我们考虑往左和往右倒的概率,以及选最左边和最右边的概率。
#include<cstdio> #include<cmath> #include<cstring> #include<algorithm> #include<iostream> #define ll long long ll a[200005]; bool vis[2005][2005][2][2]; double f[2005][2005][2][2]; int n; ll h; double p; int read(){ int t=0,f=1;char ch=getchar(); while (ch<'0'||ch>'9'){if (ch=='-') f=-1;ch=getchar();} while ('0'<=ch&&ch<='9'){t=t*10+ch-'0';ch=getchar();} return t*f; } double dp(int l,int r,int sl,int sr){ if (vis[l][r][sl][sr]) return f[l][r][sl][sr]; vis[l][r][sl][sr]=1; f[l][r][sl][sr]=0; if (l==r){ if (sl==1&&a[l-1]+h>a[l]){ if (sr) return f[l][r][sl][sr]=std::min(h,a[l+1]-a[l]); else return f[l][r][sl][sr]=std::min(h,std::max(0LL,a[l+1]-a[l]-h)); }else if (sr==0&&a[r+1]-h<a[r]){ if (sl==0) return f[l][r][sl][sr]=std::min(h,a[l]-a[l-1]); else return f[l][r][sl][sr]=std::min(h,std::max(0LL,a[l]-a[l-1]-h)); } double ans=0; if (sl) ans+=p*std::min(h,std::max(0LL,a[l]-a[l-1]-h)); else ans+=p*std::min(h,a[l]-a[l-1]); if (sr==0) ans+=(1.0-p)*std::min(h,std::max(0LL,a[l+1]-a[l]-h)); else ans+=(1.0-p)*std::min(h,a[l+1]-a[l]); return f[l][r][sl][sr]=ans; } if (sl==1&&a[l-1]+h>a[l]) return f[l][r][sl][sr]=dp(l+1,r,1,sr)+std::min(h,a[l+1]-a[l]); else if (sr==0&&a[r+1]-h<a[r]) return f[l][r][sl][sr]=dp(l,r-1,sl,0)+std::min(h,a[r]-a[r-1]); double ans=0; ans+=0.5*(1-p)*(dp(l+1,r,1,sr)+std::min(h,a[l+1]-a[l])); ans+=0.5*(p)*(dp(l,r-1,sl,0)+std::min(a[r]-a[r-1],h)); if (sl==1) ans+=0.5*p*(dp(l+1,r,0,sr)+std::min(h,std::max(0LL,a[l]-a[l-1]-h))); else ans+=0.5*(p)*(dp(l+1,r,0,sr)+std::min(h,a[l]-a[l-1])); if (sr==0) ans+=0.5*(1-p)*(dp(l,r-1,sl,1)+std::min(h,std::max(0LL,a[r+1]-a[r]-h))); else ans+=0.5*(1-p)*(dp(l,r-1,sl,1)+std::min(h,a[r+1]-a[r])); return f[l][r][sl][sr]=ans; } int main(){ n=read();h=read();scanf("%lf",&p); for (int i=1;i<=n;i++) a[i]=read(); std::sort(a+1,a+1+n); a[0]=a[1]-1e10;a[n+1]=a[n]+1e10; printf("%.9f ",dp(1,n,0,1)); }