版权声明:这是蒟蒻的BLOG,神犇转载也要吱一声哦~ https://blog.csdn.net/Dream_Lolita/article/details/85696627
【题目】
原题地址
一个餐厅有
张桌子,第
张座位数为
。先后有
群人来吃饭,人数为
中随机一个数。他们会找一张恰好能坐下的桌子坐下(找不到就离开)。求最终期望有多少个人吃饭。
【解题思路】
首先我们可以先添加
个座位
的桌子表示离开餐馆,然后按座位数排序。
考虑用期望的定义来求答案,同时 出总和和方案数。
注意到最后占据的一定是若干个区间,每个区间可以独立计算。
我们设 表示只有 的桌子被占据的人数总和以及方案数,枚举最后一张坐的桌子是什么来进行转移,这里有一个组合数 表示前 张桌子的排列种类数。
然后设 表示 这些人占据了 这些桌子的总和以及方案数,利用前缀和优化转移。
(或者我们可以设接下来设 表示前 张桌子占了 张的期望。枚举 表示 都占了, 不占,当 表示 不占,这里有一个组合数 表示前 张桌子顺序。)
复杂度
【参考代码】
#include<bits/stdc++.h>
#define pb push_back
#define mkp make_pair
#define fi first
#define se second
using namespace std;
typedef double db;
typedef long long ll;
typedef pair<db,db> pdd;
const int N=205;
int n,g,t,c[N];
db C[N][N];
pdd w[N][N],f[N][N],s[N][N];
int read()
{
int ret=0,f=1;char c=getchar();
while(!isdigit(c)) {if(c=='-')f=0;c=getchar();}
while(isdigit(c)) ret=ret*10+(c^48),c=getchar();
return f?ret:-ret;
}
pdd operator +(const pdd&a,const pdd&b){return mkp(a.fi*b.se+a.se*b.fi,a.se*b.se);}
pdd operator *(const pdd&a,const pdd&b){return mkp(a.fi+b.fi,a.se+b.se);}
void initC()
{
for(int i=0;i<N;++i)
{
C[i][i]=C[i][0]=1;
for(int j=1;j<i;++j) C[i][j]=C[i-1][j]+C[i-1][j-1];
}
}
pdd calc(int l,int r)
{
int x=min(g,l>0?c[l-1]:0),y=min(g,c[r]);
return mkp(c[r]<N?(y*(y+1)-x*(x+1))/2:0,y-x);
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("E.in","r",stdin);
freopen("E.out","w",stdout);
#endif
initC();n=read();g=read();t=read();
for(int i=0;i<n;++i) c[i]=read();
for(int i=0;i<t;++i) c[n++]=N;
sort(c,c+n);
for(int i=0;i<n;++i)
{
w[i][i]=calc(i,i);
for(int j=i-1;~j;--j) for(int k=j;k<=i;++k)
{
pdd tmp=mkp(0,C[i-j][k-j])+calc(j,k);
if(j<k) tmp=tmp+w[j][k-1];
if(i>k) tmp=tmp+w[k+1][i];
w[j][i]=w[j][i]*tmp;
}
}
for(int i=t-1;~i;--i) for(int j=n-1;~j;--j) f[i][j]=w[j][j+t-i-1];
for(int i=t-1;~i;--i) for(int j=n-1;~j;--j)
{
for(int k=i+1;k<t;++k)
f[i][j]=f[i][j]*(mkp(0,C[t-i][t-k])+w[j][j+k-i-1]+s[k][j+k-i+1]);
s[i][j]=s[i][j+1]*f[i][j];
}
pdd ans=mkp(0,0);
for(int i=0;i<n;++i) ans=ans*f[0][i];
printf("%.10lf\n",ans.fi/ans.se);
return 0;
}