J - Sushi 题解(期望dp)

题目链接

题目大意

给你n个盘子,每个盘子可能有1,2,3个披萨

你选到每个盘子的概率是一样的。

你如果选到空的盘子什么都不做

如果你选到有披萨的盘子则吃掉一个披萨

求吃完所有披萨的期望

题目思路

设现在还有u个1个盘子的披萨,v个2.....,z个3....

则显然吃掉下一个披萨的概率为(u+v+w)/n则期望为n/(u+v+w)

那么显然公式就是下面这样

\(dp[u][v][w]=n/(u+v+w)+u/(u+v+w)*dp[u-1][v][w]+v/(u+v+w)*dp[u+1][v-1][w]+w/(u+v+w)*dp[u][v+1][w-1]\)

直接记忆化搜索dp

代码

#include<set>
#include<map>
#include<queue>
#include<stack>
#include<cmath>
#include<cstdio>
#include<vector>
#include<string>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<unordered_map>
#define fi first
#define se second
#define debug printf(" I am here\n");
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> pii;
const ll INF=0x3f3f3f3f3f3f3f3f;
const int maxn=3e2+5,inf=0x3f3f3f3f,mod=1e9+7;
const double eps=1e-10;
int n,a[maxn];
double dp[maxn][maxn][maxn];
int x,y,z;
double dfs(int u,int v,int w){
    if(u==0&&v==0&&w==0) return 0;
    if(abs(dp[u][v][w])>eps) return dp[u][v][w];
    double ans=1.0*n/(u+v+w);// n/(u+v+w)的期望吃到寿司
    if(u)   ans+=1.0*u/(u+v+w)*dfs(u-1,v,w);
    if(v)   ans+=1.0*v/(u+v+w)*dfs(u+1,v-1,w);
    if(w)   ans+=1.0*w/(u+v+w)*dfs(u,v+1,w-1);
    return dp[u][v][w]=ans;
}
int main(){
    scanf("%d",&n);
    for(int i=1;i<=n;i++){
        scanf("%d",&a[i]);
        if(a[i]==1){
            x++;
        }else if(a[i]==2){
            y++;
        }else{
            z++;
        }
    }
    printf("%.10f",dfs(x,y,z));
    return 0;
}

posted @ 2020-11-15 19:26  hunxuewangzi  阅读(126)  评论(0编辑  收藏  举报