Live2D

「Snackdown 2021 Final」Queue at the Bakery 题解

link

Solution

不难看出编号为 \(i\) 的服务员我们可以让他(她?)一定服务进来的编号 \(\equiv i\bmod{m}\),那么我们就可以对于每个服务员单独考虑,然后最后加起来即是答案。

考虑设 \(f_{i,j,k}\) 表示现在还有 \(i\) 个客户,该服务员还要继续工作 \(j\) 才能休息,当前客人模 \(m\equiv k\) 的期望等待时间。不难发现,如果客人要进来,那么当 \(k=0\) 时,服务员就会去服务(/xyx) 他(她?),那么就会转移到 \(f_{i-1,j+d-1,m-1}\),贡献即为 \((f_{i-1,j+d-1,m-1}+j)\times P\),如果 \(k\not= 0\),那么肯定不是我去服务,所以贡献即为 \(f_{i-1,j-1,k-1}\times P\)。如果不进来,贡献即为 \(f_{i-1,j-1,k}\times (1-P)\)

最后答案即为:

\[\sum_{i=0}^{m-1} f_{n,0,i} \]

但是你发现复杂度有点离谱。注意到当 \(j\) 足够大的时候,那么服务员肯定是不间断服务(身体可能扛不住/xyx),所以我让他前面多增加 \(t\) 时间,那么会增加的贡献就是 $t\times $ 他后面期望服务人数。所以我们就不需要处理每个 dp,这个临界值差不多取到 \(1500\) 就可以了,听说可以更低,可能是数据不够强吧。

Code

#include <bits/stdc++.h>
using namespace std;

#define Int register int
#define MAXN 50005
#define MAXM 1505
#define MAXD 15

template <typename T> inline void read (T &t){t = 0;char c = getchar();int f = 1;while (c < '0' || c > '9'){if (c == '-') f = -f;c = getchar();}while (c >= '0' && c <= '9'){t = (t << 3) + (t << 1) + c - '0';c = getchar();} t *= f;}
template <typename T,typename ... Args> inline void read (T &t,Args&... args){read (t);read (args...);}
template <typename T> inline void write (T x){if (x < 0){x = -x;putchar ('-');}if (x > 9) write (x / 10);putchar (x % 10 + '0');}
template <typename T> inline void chkmax (T &a,T b){a = max (a,b);}
template <typename T> inline void chkmin (T &a,T b){a = min (a,b);}

int n,m,d,maxw = 1500;
double pro,dp[2][MAXM][MAXD],peo[MAXN][MAXD];

double getit (int i,int j,int k){
	return j <= maxw ? dp[i & 1][j][k] : (dp[i & 1][maxw][k] + (j - maxw) * peo[i][k]);
}

signed main(){
	read (n,m,d),scanf ("%lf",&pro);
	for (Int i = 1;i <= n;++ i)
		for (Int j = 0;j <= m - 1;++ j){
			if (j == 0) peo[i][j] = (peo[i - 1][m - 1] + 1) * pro;
			else peo[i][j] = peo[i - 1][j - 1] * pro;
			peo[i][j] += peo[i - 1][j] * (1 - pro);
		}
	for (Int i = 1;i <= n;++ i)
		for (Int j = 0;j <= maxw;++ j)
			for (Int k = 0;k <= m - 1;++ k){
				if (k == 0) dp[i & 1][j][0] = (getit (i - 1,j + d - 1,m - 1) + j) * pro;
				else dp[i & 1][j][k] = dp[i - 1 & 1][j - !!j][k - 1] * pro;
				dp[i & 1][j][k] += dp[i - 1 & 1][j - !!j][k] * (1 - pro);
			}
	double ans = 0;
	for (Int i = 0;i < m;++ i) ans += dp[n & 1][0][i];
	printf ("%.10f\n",ans);
	return 0;
}
posted @ 2022-01-26 16:01  Dark_Romance  阅读(72)  评论(1编辑  收藏  举报