AGC022F Checkers / 3.29 考试 兔子猜拳(rabbit)

给出 \(n\)\(n\) 维的点,第 \(i\) 个点的坐标是 \((x_{i, 1}, x_{i, 2}, \dots, x_{i, n})\),其中 \(x_{i, j} = [i = j]\)
接下来进行 \(n - 1\) 轮游戏,每轮会随机两只兔子决出胜负,胜利的兔子会跳到其关于输掉的兔子的对称点,然后输掉的兔子淘汰,不参与接下来的游戏。
请问,最后剩下的兔子的可能的位置的有多少种,对于 \(p\) 取模。
\(n \le 500, 10^4 + 7 \le p \le 10^9 + 7, p \in prime\)


  动态规划 结论

  神仙题。

  考虑对于输赢关系建树,输的向赢的连边。

  我们可以发现,因为每个点对于答案的贡献最后是独立的,该点最后对于答案的贡献是 \(c_i2^{dep}\)(每往向上跳贡献就会 \(\times 2\),并且 \(c_i = \pm 1\)),最后答案不同当且仅当一个点的深度不同或者一个点的系数不同。

  观察贡献,该点每多出一个儿子,\(c\) 就会 \(\times -1\),同时,这个点往上跳的同时,右边每多出一个儿子,\(c\) 就会 \(\times -1\)

  对于一个点,如果其儿子个数为 \(k\),那么会有 \(\left\lfloor \frac{k}{2} \right\rfloor\) 个儿子(整个子树)的 \(c\) 取反,同时,若 \(k \equiv 1 \pmod 2\),那么这个点的 \(c\) 会取反。

  因为我们可以让一个点的贡献计算的一部分从父亲继承(而不需要考虑整个祖先),因此,我们发现,一个点的贡献取决于:父亲的正负,自己在父亲子树中顺序的奇偶,自己儿子的奇偶。

  为了消除父亲的正负的影响,我们可以考虑差分。如果一个点的权值\(1\),那么它的贡献系数和父亲相同,如果为 \(-1\),则代表不同。

  因此一个点的贡献只和 自己在父亲子树中顺序的奇偶 以及 自己儿子的奇偶 有关了。

  因此,我们可以设一个 DP,\(f(i, j)\) 表示现在已经确定了 \(i\) 个点,其中最后一层有 \(j\) 个点儿子个数为奇数。注意层数可以直接在转移中间体现,因此是不重要的。

  然后枚举 \(x, y\),表示有 \(x\) 个点的权值为 \(1\)(和父亲相同),\(y\) 个点权值为 \(-1\)(和父亲不同),如果不考虑自己的儿子个数的奇偶,我们就会有 \(j + \frac{x + y - j}{2}\) 的权值是正数,因为每个奇数点自带一个点是正的,之后每个的儿子点两两配对(注意要保证 \(x+ y - j\equiv 0 \pmod 2\),不过是细节问题了)。

  然后为了和实际相符合,于是我们要将 \(|j + \frac{x + y - j}{2} - x|\) 个点的贡献取反(也就是让其儿子个数为奇数),于是有转移 \(f(i, j) \to f(i + x + y, |j + \frac{x + y - j}{2} - x|)\),系数是 \(\binom {i+x+y}{x+y}\binom{x+y}{x}\)

  代码,复杂度 \(\mathcal O(n^4)\)

#define rep(i, x, y) for(int i = (x); i <= (y); i++)
#define per(i, x, y) for(int i = (x); i >= (y); i--)
int main() {
	n = in;
	C[0][0] = 1; rep(i, 1, n) C[i][0] = 1;
	rep(i, 1, n) rep(j, 1, i) C[i][j] = (C[i - 1][j - 1] + C[i - 1][j]) % mod;
	f[1][0] = f[1][1] = 1;
	rep(i, 1, n - 1) {
		rep(j, 0, i) if(f[i][j]) {
			rep(x, 0, n - i)
				rep(y, 0, n - i - x)
				if(x + y >= j && ((x + y - j) % 2 == 0) && x + y)
					(f[i + x + y][abs((x + y - j) / 2 + j - x)] +=
					 1ll * f[i][j] * C[i + x + y][x + y] % mod * C[x + y][x] % mod) %= mod;
		}
	} printf("%d\n", f[n][0]);
	return 0;
}

  实际上可以继续优化,因为我们发现如果 \(i +x, j - x\) 相同,于是我们的转移就会相同,也就是我们可以这样:\(f(i, j) \to g(i + x, j - x) \to f(i + x+ y, |j + \frac{x + y - j}{2} - x|)\),可就是先枚举 \(x\),再对于用一类枚举 \(y\),然后转移系数是独立的。

  具体转移的时候,需要考虑几个细节:

  • 对于 \(x = 0\) 的时候特殊考虑,不要再中转到 \(g\) 了,这样可以强制让 \(f\) 转移到下一层以及之后的 \(g\)
  • 因此大体思路要求先转移 \(g\),再转移 \(f\)(保证 \(g\) 可能会转移到同层,\(f\) 一定转移到之后的层)。

  代码,复杂度 \(\mathcal O(n^3)\)here

posted @ 2022-04-01 20:38  Werner_Yin  阅读(117)  评论(0编辑  收藏  举报