• UVA10529 Dumb Bones


    传送门

    翻译有些不清楚,意思就是骨牌不一定要按从左到右的顺序放,可以左边放一个,右边放一个,再中间放一个

    然后每个骨牌都可能往左或往右倒,一旦倒了,倒的一边的所有骨牌都要重新放

    然后问你,最小期望放置次数是多少

    考虑每个骨牌的影响,设$f [ i ]$ 表示放$ i $个骨牌的的最小期望放置次数

    那么显然 $f [ 1 ] = 1/(1-pl-pr)$

    枚举此次放置的位置$ j $,设左边有$ L $个骨牌,右边有 $R$ 个骨牌

    那么期望花费就是左边的期望花费$f[L]$加右边的期望花费$f[R]$

    加上放最后一块的期望$frac{(1+P_lcdot f[L]+P_rcdot f[R])}{(1-P_l-P_r)}$

    $P_lcdot f[L]$ 是骨牌往左倒的期望花费,$P_rcdot f[R]$同理,注意还要保证最后放置时不倒,所以期望要再除一个成功概率

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cmath>
    #include<cstring>
    using namespace std;
    typedef long long ll;
    inline ll read()
    {
        ll x=0,f=1; char ch=getchar();
        while(ch<'0'||ch>'9') { if(ch=='-') f=-1; ch=getchar(); }
        while(ch>='0'&&ch<='9') { x=(x<<1)+(x<<3)+(ch^48); ch=getchar(); }
        return x*f;
    }
    const int N=1e3+7;
    const double INF=1e9+7;
    int n;
    double f[N],pl,pr,t;//t是放置一个骨牌的成功概率
    inline double slove(int l,int r)
    {
        return f[l]+f[r]+(1+pl*f[l]+pr*f[r])/t;
    }
    int main()
    {
        n=read();
        while(n)
        {
            scanf("%lf%lf",&pl,&pr);
            t=1.0-pl-pr;
            f[0]=0; f[1]=1/t;
            for(int i=2;i<=n;i++)
            {
                f[i]=slove(0,i-1);
                for(int j=1;j<i;j++)
                    f[i]=min(f[i],slove(j,i-j-1));
            }
            printf("%.2lf
    ",f[n]);
            n=read();
        }
        return 0;
    }

    可以发现随着 j 的变化,期望是一个下凹函数

    随着 i 的增长,下凹的位置是保持不降的,所以我们可以得出一个均摊O(n)的算法

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cmath>
    #include<cstring>
    using namespace std;
    typedef long long ll;
    inline ll read()
    {
        ll x=0,f=1; char ch=getchar();
        while(ch<'0'||ch>'9') { if(ch=='-') f=-1; ch=getchar(); }
        while(ch>='0'&&ch<='9') { x=(x<<1)+(x<<3)+(ch^48); ch=getchar(); }
        return x*f;
    }
    const int N=1e3+7;
    const double INF=1e9+7;
    int n;
    double f[N],pl,pr,t;
    inline double slove(int l,int r)
    {
        return f[l]+f[r]+(1+pl*f[l]+pr*f[r])/t;
    }
    int main()
    {
        n=read();
        while(n)
        {
            scanf("%lf%lf",&pl,&pr);
            t=1.0-pl-pr;
            f[0]=0; f[1]=1/t;
            int pos=0;//pos记录上一次下凹的位置
            for(int i=2;i<=n;i++)
            {
                f[i]=slove(pos,i-pos-1);
                for(int j=pos+1;j<i;j++)//下凹位置保持不降
                {
                    double s=slove(j,i-j-1);
                    if(s<=f[i]) { f[i]=s; pos=j; }
                    else break;
                }
            }
            printf("%.2lf
    ",f[n]);
            n=read();
        }
        return 0;
    }
  • 相关阅读:
    【leetcode】416. Partition Equal Subset Sum
    【leetcode】893. Groups of Special-Equivalent Strings
    【leetcode】892. Surface Area of 3D Shapes
    【leetcode】883. Projection Area of 3D Shapes
    【leetcode】140. Word Break II
    【leetcode】126. Word Ladder II
    【leetcode】44. Wildcard Matching
    【leetcode】336. Palindrome Pairs
    【leetcode】354. Russian Doll Envelopes
    2017.12.22 英语面试手记
  • 原文地址:https://www.cnblogs.com/LLTYYC/p/9804639.html
Copyright © 2020-2023  润新知