zoukankan      html  css  js  c++  java
  • Codeforces 596D Wilbur and Trees

    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));
    }

     

     

  • 相关阅读:
    [ACM] hdu 1671 Phone List (特里)
    Android 记录的(MediaRecorder)而播放(MediaPlayer)
    菜鸟进阶Android Touch事件传递(四)
    九度oj题目&amp;吉大考研11年机试题全解
    怎样取消shutdown关机命令?-shutdown命令的使用解析
    怎样下载并编译Android4.0内核源代码goldfish(图文)
    三角函数图像
    HTML里面Textarea换行总结
    java中使用队列:java.util.Queue
    ContentProvider简单介绍
  • 原文地址:https://www.cnblogs.com/qzqzgfy/p/5667594.html
Copyright © 2011-2022 走看看