Codeforces Round#331(Div.2).D-Wilbur and Trees,例のDFS

7204 ワード

問題の出典:http://www.cnblogs.com/qscqesze/p/4971459.html ゞ膜一发卿学姐Orz...........ゞ
題意はあなたにn本の木をあげて、すべての木の高さはすべて同じhで、およびpで、木を切る時左に倒れる確率、(1-pは右に倒れる確率)、それから2行目はあなたに木の座標を教えていません.木を切る人は毎回0.5の確率で一番左の木を切り、0.5の確率で一番右の木を切り、1本の木を切った後、この木は左か右に倒れ、倒れたときに別の木にぶつかったら、その木も同じ方向に倒れ、ある木を切った後、地面の長さを覆う数学の期待を聞く.
考え方:その时私达はこの问题を见て直接放弃するつもりで、私达はすべて1本のdpだと思って、その上私个人はまた数学の期待に対して少しぼんやりしています(高校の知识はすべて先生に返して、すべての情况の確率*长さの和です).だからこんにゃくの私たちは作れません.その後、問題解を見てみると、本当に難しくない問題(もちろん、自分の頭が悪い)であることがわかりました.この問題はdpを使う必要はありません.与えられた状況ごとに、私たちが考えなければならないのは以下のいくつかの条件です.区間はl-r:lが一番左の木で、rが一番右の木です.1一番左の木を切る(1).左の木を切って左の木を左に倒す場合は、l-1が右に倒れるかどうか、距離はmin(h,v[l]-v[l-1]-f 1(右に倒れるかどうか)*h)であることを考慮する必要があるので、ここのf 1は0であればl-1が左に着き、1であればl-1が右に倒れることを明らかに表す.明らかにまだ終わっていないので、自然に次の区間(l+1,r,0,f 2)をしなければならない.次の区間lに対してl-1に相当するため、左に倒れるとf 1が0になる.同様に、r+1が左または右に倒れるかどうかを判断するためにf 2を設定する.
(2).左の木を切り、左の木を右に倒すのであれば、この木が何本倒せるかを判断する必要があります.右にLを倒せば、この距離は(v[L]-v[l]+h)L+1本目を倒せないに違いないので(存在するなら)考えてみましょう.L=rであれば距離が変わります.r+1が左に倒れるかどうかも考えなければならないので、距離は:(v[r]-v[l]+min(h,v[r+1]-v[r]-f 2*h))であるべきです.この場所は一度書き逃します:(v[r]-v[l]+h f 2*h)が、実はhはv[r+1]-v[r]より大きい可能性が高いので、xjbは書けません!
2.一番右の木を切るのも同じで、右に倒れるのと左に倒れるのと同じである.右に倒れるのは自然に簡単である.すなわちmin(h,v[r+1]-v[r]-f 2*h)+dfs(l,r-1,f 1,0);左に倒れると、自然にlまで押すことができるかどうかを判断する必要があり、できれば(v[r]-v[l]+min(h,v[l]-v[l-1]-f 1*h))である.;Rを倒せる一番左の木にできない場合はv[r]-v[R]+h+dfs(l,R,f 1,1)とする.ここではminを取らず、R-1には当たらないのでh肯定
#include<iostream>
#include<stdio.h>
#include<algorithm>
using namespace std;
#define maxn 2005
const int inf = 1e9;
double dp[maxn][maxn][2][2];
int vis[maxn][maxn][2][2];
int n;
double h,p;
int v[maxn];
int dl[maxn],dr[maxn];
double dfs(int l,int r,int f1,int f2) // l,r->1-n f1:l-1        ,f2:r+1          
{
    //cout<<l<<" "<<r<<" "<<f1<<" "<<f2<<endl;
    if(vis[l][r][f1][f2])
        return dp[l][r][f1][f2];
    if(l>r)
        return 0;
    vis[l][r][f1][f2]=1; //
    //        

    double ans = dp[l][r][f1][f2];
    ans+=p*0.5* (   min(h*1.00,v[l]-v[l-1]-f1*h) + dfs(l+1,r,0,f2) );
    // l           ,f1=1    l-1      ,        
    ans+=(1-p)*0.5*(min(h*1.0,v[r+1]-v[r]-f2*h)+dfs(l,r-1,f1,0));
    // r      ,f2=1   r+1      ,

    int L = dr[l];// l      ,       
    int R = dl[r];// r      ,       

    if(R<=l) //    r          (l),              l。
        ans+=p*0.5*( v[r]-v[l] +  min(h,v[l]-v[l-1]-f1*h) );//    l-1     
    else    //      l,         。
        ans+=p*0.5*( v[r]-v[R]+h+dfs(l,R-1,f1,1) ); //  r        R
    if(L>=r) //  l    r,  
        ans+=(1-p)*0.5*(v[r]-v[l]+min(h,v[r+1]-v[r]-f2*h));
    else
        ans+=(1-p)*0.5*(v[L]-v[l]+h+dfs(L+1,r,1,f2));
    dp[l][r][f1][f2] = ans;
    return ans;
}
int main()
{
    scanf("%d%lf",&n,&h);
    scanf("%lf",&p);
    for(int i=1;i<=n;i++)
        scanf("%d",&v[i]);
    sort(v+1,v+1+n);
    v[n+1]=inf;
    v[0]=-inf;
    dr[n]=n;dl[1]=1;     //dl   i              ,  dr             
    for(int i=n-1;i>=1;i--){
        if(v[i+1]-v[i]<h)
            dr[i]=dr[i+1];
        else 
            dr[i]=i;
    }
    for(int i=2;i<=n;i++){
        if(v[i]-v[i-1]<h)
            dl[i]=dl[i-1];
        else
            dl[i]=i;
    }
    printf("%.15f
"
,dfs(1,n,0,0)); }