题目链接
题目大意
给你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
");
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;
}