zoukankan      html  css  js  c++  java
  • JAGSpring2015C Casino

    Link

    (f_i)表示有(i)元钱时的获胜概率,那么我们有:(f_0=0,f_n=1,f_m=maxlimits_{x=1}^{min(m,n-m)}pf_{m+x}+(1-p)f_{m-x})

    (p=0):获胜概率为(0),可行的决策集合为([1,m])

    (p=1):获胜概率为(1),可行的决策集合为([1,m])

    (p=frac12):获胜概率为(frac mn),可行的决策集合为([1,min(m,n-m)])

    (p>frac12)

    直觉告诉我们此时选择(x=1)是最优的。因为概率对我们是有利的,所以时间拖得越长越有利。
    不难验证(x=1)也是唯一的最优策略。
    那么此时的(f)就是一个经典的赌徒输光模型,令(q=frac{1-p}p),那么(f_m=frac{1-q^m}{1-q^n})

    (p<frac12)

    直觉告诉我们此时(x)应该尽可能大,也就是说(x=min(m,n-m))
    事实上这确实是最优的策略,但是还存在其它的最优策略。
    首先代入得到:

    [f_m= egin{cases} pf_{2m}&2mle n\ p+(1-p)f_{2m-n}&2m>n end{cases} ]

    然后我们就可以利用这个式子暴力迭代计算(f_m),最多(10^4)层即可。
    注意到答案实际上只与(frac mn)有关,因此我们考虑用(f(x))代替(f(nx))来进行计算。
    那么也就是:

    [f_x= egin{cases} pf_{2x}&2xle 1\ p+(1-p)f_{2x-1}&2x>1 end{cases} ]

    考虑将(x)展开为二进制,若(x=sumlimits_{ige0}2^{-e_i}),那么(f(x)=sumlimits_{ige0}q^ip^{e_i}),其中(q=frac{1-p}p)
    我们可以推出(forall xge yge 0,f(x+y)ge f(x)+qf(y))。(证明比较复杂,此处省略)
    那么我们现在需要做的就是找到取等号的充要条件,先将(x,y)写成(frac{m+d}n,frac{m-d}n)的形式。
    (frac mn)二进制展开,考虑其中的每一位01(frac mn=a2^{e+2}+2^e+b(ainmathbb N,bin[0,2^e))),那么可行的(d)的取值就是((2^epm b)n)

    #include<set>
    #include<cmath>
    #include<cstdio>
    #include<cstdlib>
    #include<algorithm>
    const double eps=1e-10;
    int n,m;double p;std::set<int>ans;
    double cal(int n,int m,int d)
    {
        if(!n||d>10000) return 0;
        if(n==m) return 1;
        int q=std::min(n,m-n);
        return p*cal(n+q,m,d+1)+(1-p)*cal(n-q,m,d+1);
    }
    void getans(int n,int m)
    {
        for(;n&&n<m;m/=2,n%=m)
        {
    	ans.insert(std::min(n,m-n));
    	if(m&1) break;
        }
    }
    void print(double ans,int c)
    {
        printf("%.10lf
    %d
    ",ans,c);
        if(c<=200) for(int i=1;i<=c;++i) printf("%d ",i);
        else
        {
    	for(int i=1;i<=100;++i) printf("%d ",i);
    	for(int i=c-99;i<=c;++i) printf("%d ",i);
        }
        exit(0);
    }
    int main()
    {
        scanf("%lf%d%d",&p,&n,&m),p/=100;
        if(fabs(p)<eps||fabs(p-1)<eps) print(p,n);
        if(fabs(p-0.5)<eps) print(1.0*n/m,std::min(n,m-n));
        if(0.5-eps<p) print((1-pow((1-p)/p,n))/(1-pow((1-p)/p,m)),1);
        printf("%.10lf
    ",cal(n,m,0)),getans(n,m);
        printf("%d
    ",(int)ans.size());
        for(int x:ans) printf("%d ",x);
    }
    
  • 相关阅读:
    基于OWin的Web服务器Katana发布版本3
    如何在.NET上处理二维码
    .NET开源OpenID和OAuth解决方案Thinktecture IdentityServer
    ASP.NET Identity V2
    Azure Redis Cache
    CentOS 7 安装RabbitMQ 3.3
    ASP.Net MVC 5 in Xamarin Studio 5.2
    Centos 7.0 安装Mono 3.4 和 Jexus 5.6
    CentOS下GPT分区(转)
    CentOS下使用LVM进行分区(转)
  • 原文地址:https://www.cnblogs.com/cjoierShiina-Mashiro/p/12556682.html
Copyright © 2011-2022 走看看