Public Easy Round #2 E 2048

\(f\):长度为 \(i\) 的栈,栈底先填一个 \(j\) 的期望得分

  • case 1 : 直接把 \(j\) 升级。
  • case 2 : 下一个填比 \(j\) 大的,那我 \(j\) 就可以直接摆烂停止考虑,直接归约。
  • case 3 : 下一个比 \(j\) 小,那就要小心控制使得 \(j\) 不被升级。

因此得到另外的 \(dp\) 定义:

\(j\) 升级需要再造一个 \(j\) 在后面,因此
\(g\):长度为 \(i\) 的栈,一波操作后得到单个 \(j\) 的 概率/期望得分。

  • case 1 : 人品爆发直接随一个出来
  • case 2 : 从 \(j - 1\) 合并上来,要先造一个 \(j - 1\) 再造一个 \(j - 1\)

显然对于 \(g\) 的转移我们不用维护更多东西。

考虑 \(f\) 的其他转移。

怎样使得 \(j\) 再之后不被升级?
首先因为填的数比他小,因此这个数无论怎样被合并都不应该超越他,否则会被升级。
\(h\):长度为 \(i\) 的栈,乱填一波,最后开头是个 \(j\) 的期望得分(好像不需要概率信息)。

case
要造一个数 \(j\) 出来,那就先合一个出来,然后让之后的东西不能给他升级(可能直接出比他大的,也可能比他小的合不上去)。
然后剩下部分的期望得分,一个是填出来开头比他小(归约至 \(j\)),另一个是填出来比他大(当且仅当开局就大,归约至 \(f\))。

参考实现

int main() {
	read(n),read(m);
	int Tot = 0;
	for (int i = 1; i <= m; ++i) read(a[i]) , Tot += a[i];
	Tot = Qpow(Tot , mod - 2);
	Power[0] = 1;
	for (int i = 1; i <= m; ++i) p[i] = Mul(Tot , a[i]) , g[0][1][i] = p[i];
	for (int i = 1; i <= n + m; ++i) Power[i] = Mul(Power[i - 1] , 2);
	
	for (int i = 2; i <= n; ++i) {
		for (int j = 1; j <= n + m; ++j) {
			g[0][i][j] = Add(p[j] , Mul(g[0][i][j - 1] , g[0][i - 1][j - 1]));
			g[1][i][j] = Add(Mul(Power[j] , Mul(g[0][i][j - 1] , g[0][i - 1][j - 1])) , Add(Mul(g[0][i - 1][j - 1] , g[1][i][j - 1]) , Mul(g[1][i - 1][j - 1] , g[0][i][j - 1])));
			h[i][j] = Add(Mul(g[1][i][j] , Sub(1 , g[0][i - 1][j])) , Mul(g[0][i][j] , Add(Ph[i - 1][j - 1] , Sf[i - 1][j + 1])));
			Ph[i][j] = Add(Ph[i][j - 1] , h[i][j]);
		}
		for (int j = n + m; j >= 1; --j) {
			f[i][j] = Add(Add(Mul(g[0][i - 1][j] , Add(f[i][j + 1] , Power[j + 1])) , g[1][i - 1][j]) , Add(Ph[i - 1][j - 1] , Sf[i - 1][j + 1]));
			Sf[i][j] = Add(Sf[i][j + 1] , Mul(f[i][j] , p[j]));
		}
	}
	
	write(Mul(Sf[n][1] , ((mod + 1) >> 1)));
	return 0;
}
posted @ 2022-05-08 22:28  Reanap  阅读(30)  评论(0编辑  收藏  举报