zoukankan      html  css  js  c++  java
  • ZOJ 3329 One Person Game

    思路

    典型的一类概率dp问题
    逆推,用dp[i]表示从n到i的期望次数,p[i]表示获得i分数的概率,px表示分数清零的概率
    容易想到题目中的转移方程为(dp[j]=sum_{i}^{sumk}dp[j+i]p[i]+dp[0]px+1)
    显然从dp[n]开始,要求dp[0]
    可是每个状态的转移都包含了dp[0],转移出现环了怎么办?
    高斯消元?可是n=500,T=300,根本过不去
    发现并不每个都互相依赖,而是都依赖于dp[0],那我们找出dp[x]与dp[0]的关系,问题似乎就可以解决了
    由于期望的线性性,我们尝试列出一个线性的方程组的形式(或者说就是给dp[0]配个系数)

    [dp[x]=a_xdp[0]+b_x ]

    把它带入转移方程中,得到

    [dp[j]=sum_{i}^{sumk}(a_{i+j}dp[0]+b_{i+j})p[i]+dp[0]px+1 ]

    尝试把它变形回原来的形式

    [dp[j]=dp[0](px+sum_{i}^{sumk}a_{i+j}p[i])+sum_{i}^{sumk}b_{i+j}+1 ]

    把他和原式(dp[x]=a_xdp[0]+b_x)对应,得到

    [a[j]=(px+sum_{i}^{sumk}a_{i+j}p[i]) ]

    [b[j]=1+sum_{i}^{sumk}b_{i+j} ]

    这样a和b就可以逆推出来了
    然后dp[0]就等于b[0]/(1-a[0])
    然后就好了

    代码

    #include <cstdio>
    #include <algorithm>
    #include <cstring>
    using namespace std;
    int T,n,k1,k2,k3,ax,bx,cx;
    double p[700],P,a[700],b[700];
    int main(){
        scanf("%d",&T);
        while(T--){
            memset(p,0,sizeof(p));
            memset(a,0,sizeof(a));
            memset(b,0,sizeof(b));
            scanf("%d %d %d %d %d %d %d",&n,&k1,&k2,&k3,&ax,&bx,&cx);
            P=1.0/(k1*k2*k3);
            for(int i=1;i<=k1;i++)
                for(int j=1;j<=k2;j++)
                    for(int k=1;k<=k3;k++)
                        if(i!=ax||j!=bx||k!=cx)
                            p[i+j+k]+=P;
            for(int i=n;i>=0;i--){
                a[i]=P,b[i]=1;
                for(int k=0;k<=k1+k2+k3;k++)
                    a[i]+=a[i+k]*p[k],b[i]+=b[i+k]*p[k];
            }
            double ans=b[0]/(1-a[0]);
            printf("%.15lf
    ",ans);
        }
        return 0;
    }
    
  • 相关阅读:
    【iOS】去掉Tabbar顶部线条
    iOS中控制器的释放问题
    码云平台帮助文档_V1.2
    iOS键盘 样式/风格
    cocoapods的安装 升级版
    Unity异常捕获
    tomcat和jdk的安装配置
    Unity读取Excel表格
    NFS
    K8S存储相关yaml
  • 原文地址:https://www.cnblogs.com/dreagonm/p/10527521.html
Copyright © 2011-2022 走看看