CF1349D Slime and Biscuits

题目链接

考虑停在每个人的贡献。设 \(E_i\) 表示最终停在第 \(i\) 个人的 概率 \(\times\) 步数 之和,那么 \(Ans = \sum_{i}E_i\)。但是 \(E_i\) 仍然不好算,因为中间可能突然停到了另一个人上。于是我们设 \(E_i'\) 表示假设只有在第 \(i\) 个人处集齐才停止的期望步数,那么就可以用类似随机游走的模型来方便地搞了。

考虑 \(E\)\(E'\) 的关系:

\[E_i = E_i' - \sum_{j \not= i} P_jC_{j \to i} + E_j \]

即考虑真实情况下可能会停在其它的地方,而我们却又将其算上了。其中 \(P_j\) 表示停在 \(j\) 的概率,\(C_{j \to i}\) 表示在假设只有在第 \(i\) 个人处集齐才停止 的情况下,从全部在 \(j\) 到全部在 \(i\) 的期望步数。显然 \(C_{j \to i}\) 对于所有的 \((j,i)\) 都是一样的。

再推一下式子:

\[\sum E_i = E_{i}' - \sum_{j \not= i}P_jC \]

\[ans = E_{i}' - \sum_{j \not= i}P_jC \]

\[\begin{aligned} n \times ans &= \sum_i E_i' - C(n-1)\sum_jP_j\\ &= \sum_i E_i' - C(n-1) \end{aligned}\]

现在考虑求 \(E_i'\)。因为我们拆开考虑了,\(i\) 以外的人都可以看作一样的,因此可以用 \(i\) 有多少饼干作为状态。设 \(f_i\) 表示当前那个人拥有 \(i\) 个饼干,一直到第 \(i\) 个人拥有全部饼干,的期望步数。于是 \(E_i' = f_{a_i}\)\(C_{j \to i} = f_0\)

考虑求解 \(f_i\)。枚举下一步操作选中的饼干拥有者以及传向的人的类型:(设 \(\sum a_i = m\)

\[f_i = 1 + \frac{i}{m} f_{i - 1} + \frac{m - i}{m} (\frac{1}{n-1}f_{i+1} + \frac{n-2}{n-1}f_i) \]

特别地:

\[f_0 = 1 + \frac{1}{n-1}f_1 + \frac{n - 2}{n - 1}f_0 \]

\[f_m = 0 \]

然后就可以高斯消元了。

然而还是太麻烦。可以用分手是祝愿(或者线性生物)的套路(好像还不太一样):考虑从 \(i\) 变为 \(i + 1\) 的期望步数,即设 \(g_i = f_i - f_{i + 1}\)(后缀差分数组),那么就有 \(f_i = \sum_{j = i}^mg_j\),然后继续化简:

\[\begin{aligned} \sum_{j = i}^mg_j &= 1 + \frac{i}{m}\sum_{j = i - 1}^m g_j + \frac{m-i}{m}(\frac{1}{n-1} \sum_{j = i + 1}^m g_j + \frac{n-2}{n-1}\sum_{j = i}^m g_j)\\ \sum_{j = i}^mg_j &= 1 + \frac{i}{m}\sum_{j = i - 1}^m g_j + \frac{m-i}{m}(\sum_{j = i + 1}^m g_j + \frac{n-2}{n-1}g_i)\\ \sum_{j = i}^mg_j &= 1 + \frac{i}{m}\sum_{j = i - 1}^m g_j + \frac{m-i}{m}\sum_{j = i + 1}^m g_j + \frac{m-i}{m}\frac{n-2}{n-1}g_i\\ g_i &= 1 + \frac{i}{m}g_{i-1} + \frac{i}{m} g_i + \frac{m - i}{m}\frac{n - 2}{n - 1}g_i\\ g_i &= (n-1)\frac{m}{m-i}(1 + \frac{i}{m}g_{i-1}) \end{aligned}\]

然后就可以直接递推了。

\(Code:\)

int main() {
	read(n);
	for (int i = 1; i <= n; ++i)	read(a[i]), m += a[i];
	init();
	g[0] = n - 1;
	for (int i = 1; i <= m; ++i)
		g[i] = inv[m - i] * (1ll * m * (n - 1) % P + 1ll * i * (n - 1) % P * g[i - 1] % P) % P;
	for (int i = m; ~i; --i)	f[i] = (f[i + 1] + g[i]) % P;
	ll S = 0;
	for (int i = 1; i <= n; ++i)	E_[i] = f[a[i]], S = (S + E_[i]) % P;
	ll C = f[0];
	ll ans = inv[n] * (S - C * (n - 1) % P) % P;
	printf("%lld\n", (ans % P + P) % P);
	return 0;
}

另解

posted @ 2020-09-24 10:21  JiaZP  阅读(181)  评论(0编辑  收藏  举报