Gym101623E English Restaurant
Link
先将\(a_i\)升序排序,并将大于\(g\)的\(a_i\)变成\(g\)。
设\(p_{i,j}\)表示只占\([i,j]\)的桌子的期望,\(q_{i,j}\)表示\([1,i)\)的桌子占了\(j\)张的期望,这都可以利用区间dp求出。
\(p_{i,j}\):考虑枚举最后占的桌子\(k\),注意要乘上\({j-i\choose k-i}\)表示顺序,即\(p_{i,j}=\sum\limits_{k=i}^j\frac{a_k-a_{i-1}}g{j-i\choose k-i}p_{i,k-1}p_{k+1,j}\)。
\(q_{i,j}\):考虑枚举\(k\)表示占据\([k,i)\)且\(k-1\)未被占据,注意要乘上\({j\choose i-k}\)表示顺序,即\(q_{i,j}=\sum\limits_{k=\max(0,i-j)}^i{j\choose i-k}p_{k,i-1}q_{k-1,j-i+k}\)。
然后我们考虑如何计算答案。
假设现在桌子大小为\(a_i\),有一个\(a_j\)人的团体占了它,那么此时所有\([j,i]\)的桌子都一定已经被占满。
枚举\([1,i]\)中总共占了\(k\)张桌子,那么对答案的贡献就是\((\sum\limits_{l=i-j+1}^k({\frac{a_i}g})^{k-l}{l-1\choose i-j}q_{j-1,l-(i-j+1)})p_{j,i-1}(\frac{\sum\limits_{l=a_{j-1}+1}^{a_i}l}g){y\choose k}(1-\frac{a_i}g)^{t-k}\)。
#include<cmath>
#include<cstdio>
#include<algorithm>
using ld=double;
const int N=107;
ld C[N][N],p[N][N],q[N][N];int a[N];
int read(){int x;scanf("%d",&x);return x;}
int Sigma(int l,int r){return (r-l+1)*(l+r)/2;}
int main()
{
int n=read(),g=read(),t=read();ld ans=0;
for(int i=1;i<=n;++i) a[i]=std::min(g,read());
std::sort(a+1,a+n+1),q[0][0]=1;
for(int i=0;i<=std::max(n,t);++i) for(int j=C[i][0]=1;j<=i;++j) C[i][j]=C[i-1][j]+C[i-1][j-1];
for(int i=1;i<=n+1;++i) p[i][i-1]=1;
for(int i=n;i;--i) for(int j=i;j<=n;++j) for(int k=i;k<=j;++k) p[i][j]+=1.0*(a[k]-a[i-1])/g*p[i][k-1]*p[k+1][j]*C[j-i][k-i];
for(int i=1;i<=n;++i) for(int j=0;j<i;++j) for(int k=i;k&&i<=j+k;--k) q[i][j]+=p[k][i-1]*q[k-1][j-i+k]*C[j][i-k];
for(int i=1;i<=n;++i)
for(int j=1;j<=i;++j)
{
ld sum=0;
for(int k=i-j+1;k<=t;++k)
{
sum=sum*a[i]/g+q[j-1][k-i+j-1]*C[k-1][i-j];
ans+=sum*p[j][i-1]*Sigma(a[j-1]+1,a[i])/g*C[t][k]*pow(1.0*(g-a[i])/g,t-k);
}
}
printf("%.10lf",ans);
}