【区间DP+期望】Gym101623E English Restaurant

版权声明:这是蒟蒻的BLOG,神犇转载也要吱一声哦~ https://blog.csdn.net/Dream_Lolita/article/details/85696627

【题目】
原题地址
一个餐厅有 n n 张桌子,第 i i 张座位数为 c i c_i 。先后有 t t 群人来吃饭,人数为 [ 1 , g ] [1,g] 中随机一个数。他们会找一张恰好能坐下的桌子坐下(找不到就离开)。求最终期望有多少个人吃饭。 n , t 100 , g , c i 200 n,t\leq 100,g,c_i\leq 200

【解题思路】
首先我们可以先添加 n n 个座位 + +\infty 的桌子表示离开餐馆,然后按座位数排序。

考虑用期望的定义来求答案,同时 DP \text{DP} 出总和和方案数。

注意到最后占据的一定是若干个区间,每个区间可以独立计算。

我们设 f i , j f_{i,j} 表示只有 [ i , j ] [i,j] 的桌子被占据的人数总和以及方案数,枚举最后一张坐的桌子是什么来进行转移,这里有一个组合数 ( j i k i ) {j-i\choose k-i} 表示前 j i j-i 张桌子的排列种类数。

然后设 g i , j g_{i,j} 表示 [ i , t ] [i,t] 这些人占据了 [ j , n ] [j,n] 这些桌子的总和以及方案数,利用前缀和优化转移。

(或者我们可以设接下来设 g i , j g_{i,j} 表示前 i i 张桌子占了 j j 张的期望。枚举 k k 表示 i k + 1 i i-k+1\sim i 都占了, i k i-k 不占,当 k = 0 k=0 表示 i i 不占,这里有一个组合数 ( j k ) {j\choose k} 表示前 j j 张桌子顺序。)

复杂度 O ( n 3 ) O(n^3)

【参考代码】

#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;
}

猜你喜欢

转载自blog.csdn.net/Dream_Lolita/article/details/85696627