zoukankan      html  css  js  c++  java
  • 【CodeForces 261B】Maxim and Restaurant(DP,期望)

    题目链接

    第一种解法是$O(n^3*p)$的:
    f[i][j][k]表示前i个人进j个人长度为k有几种方案(排列固定为123..n时)。
    $f[i][j][k]=f[i-1][j][k]+f[i-1][j-1][k-a[i]]$
    最外层枚举t表示被卡的那个人。i=t时不加上f[i-1][j-1][k-a[i]]。
    $ans={{(sum f[n][j][k]*j*j!*(n-1-j)!)+(sum f[n][n][k]*n)}}/(n!)$。


    可以看看这篇题解

    #include<cstdio>
    #include<cstring>
    #define N 55
    int n,p,a[N];
    double f[N][N][N],ans,c[N]= {1};
    int main(){
        scanf("%d",&n);
        for(int i=1; i<=n; i++){
            scanf("%d",&a[i]);
            c[i]=c[i-1]*i;
        }
        scanf("%d",&p);
        for(int t=0; t<=n; t++){
            memset(f,0,sizeof f);
            f[0][0][0]=1;
            for(int i=1; i<=n; i++)
                for(int j=0; j<=i; j++)
                    for(int k=0; k<=p; k++){
                        f[i][j][k]=f[i-1][j][k];
                        if(j>=1&&t!=i&&k>=a[i])f[i][j][k]+=f[i-1][j-1][k-a[i]];
                    }
            for(int j=1; j<n; j++)
                for(int k=1; k<=p; k++)if(a[t]+k>p)
                    ans+=c[j]*c[n-1-j]/c[n]*f[n][j][k]*j;
            for(int k=1; k<=p; k++)ans+=f[n][n][k]*n;
        }
        printf("%lf",ans);
    }

    还可以更高效,$O(n^2*p)$
    参考题解

    f[i][j][k]表示前i个人至少进j个人这j个人的长度和为k有几种方案(排列为123..n时)。
    那么$ans=(sum f[n][j][k]*j!*(n-j)!/(n!)$。

    我原来不太理解为什么至少j个人就是这么推,问了下队友,说是因为没有卡后面的,所以有可能可以进更多人。
    其实第一种方法算的f也是至少j个人,然后在后面累加ans时再卡住第j+1个人。

    并且可以用滚动数组优化为2维数组。

    #include<cstdio>
    #define N 51
    int n,a[N],p;
    double fac[N]= {1},f[N][N],tol,ans;
    int main()
    {
        scanf("%d",&n);
        for(int i=1; i<=n; i++)
        {
            scanf("%d",a+i);
            fac[i]=fac[i-1]*i;
            tol+=a[i];
        }
        scanf("%d",&p);
        if(tol<=p)
        {
            printf("%d",n);
            return 0;
        }
        f[0][0]=1;
        for(int i=1; i<=n; i++)
            for(int j=n-1; j>=0; j--)
                for(int k=0; k+a[i]<=p; k++)
                    f[j+1][k+a[i]]+=f[j][k];
        for(int j=1; j<=n; j++)
            for(int k=0; k<=p; k++)
                ans+=f[j][k]*fac[j]*fac[n-j];
        ans/=fac[n];
        printf("%lf",ans);
    }
      
  • 相关阅读:
    Android关机流程源码分析
    开关机画面
    android camera
    深入分析AIDL原理
    VMware 虚拟机里连不上网的三种解决方案
    查看Linux中自带的jdk ,设置JAVA_HOME
    Hadoop三种模式安装教程(详解)
    Java ArrayList遍历删除问题
    idea git的使用(四)git建立分支与合并分支
    SpringBoot非官方教程 | 终章:文章汇总
  • 原文地址:https://www.cnblogs.com/flipped/p/5698430.html
Copyright © 2011-2022 走看看