【题目】
原题地址
一个餐厅有
n
n
n张桌子,第
i
i
i张座位数为
c
i
c_i
ci。先后有
t
t
t群人来吃饭,人数为
[
1
,
g
]
[1,g]
[1,g]中随机一个数。他们会找一张恰好能坐下的桌子坐下(找不到就离开)。求最终期望有多少个人吃饭。
n
,
t
≤
100
,
g
,
c
i
≤
200
n,t\leq 100,g,c_i\leq 200
n,t≤100,g,ci≤200
【解题思路】
首先我们可以先添加
n
n
n个座位
+
∞
+\infty
+∞的桌子表示离开餐馆,然后按座位数排序。
考虑用期望的定义来求答案,同时 DP \text{DP} DP出总和和方案数。
注意到最后占据的一定是若干个区间,每个区间可以独立计算。
我们设 f i , j f_{i,j} fi,j表示只有 [ i , j ] [i,j] [i,j]的桌子被占据的人数总和以及方案数,枚举最后一张坐的桌子是什么来进行转移,这里有一个组合数 ( j − i k − i ) {j-i\choose k-i} (k−ij−i)表示前 j − i j-i j−i张桌子的排列种类数。
然后设 g i , j g_{i,j} gi,j表示 [ i , t ] [i,t] [i,t]这些人占据了 [ j , n ] [j,n] [j,n]这些桌子的总和以及方案数,利用前缀和优化转移。
(或者我们可以设接下来设 g i , j g_{i,j} gi,j表示前 i i i张桌子占了 j j j张的期望。枚举 k k k表示 i − k + 1 ∼ i i-k+1\sim i i−k+1∼i都占了, i − k i-k i−k不占,当 k = 0 k=0 k=0表示 i i i不占,这里有一个组合数 ( j k ) {j\choose k} (kj)表示前 j j j张桌子顺序。)
复杂度 O ( n 3 ) O(n^3) O(n3)
【参考代码】
#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;
}