npcapc_2024_d Two Box/【PR #15】黑白球染色

npcapc_2024_d Two Box/【PR #15】黑白球染色

题意

\(m\) 个球,一开始全部是白色。

\(n\) 次操作,每次操作可以把某个球的颜色反转。

有一个长度为 \(n\) 的要求序列 \(a_i\)\(a_i\) 表示第 \(i\) 次操作后编号 \(>a_i\) 的球必须是白色。

\(q\) 次修改,每次修改一个 \(a_i\),你要输出修改后有多少种操作序列满足要求序列。

\(n,q \le 3 \times 10^4, m \le 15\)

原题题解翻译

D - 两个盒子 题解

  • 部分分1\(N \leq 2000\)\(M \leq 10\)\(Q = 1\)

可以通过使用状态为 \(dp[i][j]\) 的二进制动态规划(bit DP)来解决这个问题,其中 \(dp[i][j]\) 表示进行 \(i\) 次操作后,黑盒子中球的状态为 \(j\)。时间复杂度为 \(\mathrm{O}(N2^MMQ)\)

  • 部分分2\(Q = 1\)

按照球 \(M,M - 1,\cdots,1\) 的顺序来确定它们的行为。对于球 \(k\) 而言,在大多数情况下,球 \(k\) 在其能存在于黑盒中的最大区间 \([l,r]\) 内被选择的次数为偶数次。这里所说的“大多数情况”是指,如果该区间在第 \(N\) 次操作后仍然包含在内,那么即使球 \(k\) 被选择奇数次也没问题。

在此,针对每个最大区间 \([l,r]\) 记录剩余操作次数,然后进行动态规划。状态转移方面,首先计算在 \([l,r]\) 中确定球 \(k + 1,k + 2,\cdots,M\) 的行为后剩余的操作次数。然后,如果该区间不包含整个区间的右端点,就进行使用偶数个球的状态转移。也就是说,对于数列 \(f_0,f_1,\cdots,f_d\),只需计算数列 \(g_i = \sum_{j \leq i,j = i \bmod 2} f_j \binom{j}{i}\) 即可。这可以利用卷积在 \(\mathrm{O}(d\log d)\) 的时间复杂度内计算出来。

请参考以下图表,这是 \(N = 6\)\(M = 3\)\(A = (1,3,2,2,3,1)\) 时的情况。例如,从下往上数第 \(3\) 层,考虑球 \(3\) 能存在于黑盒中的最大区间 \([2,3]\) 。由于对球 \(3\) 选择使用或不使用时,剩余操作次数分别为 \(0\)\(2\),所以对应的多项式为 \(x^2 + 1\)

从下往上数第 \(2\) 层,考虑球 \(2\) 能存在于黑盒中的最大区间 \([2,6]\) 。在 \([2,6]\) 中确定球 \(3\) 的行为后,剩余操作次数的生成函数为 \((x^2+1) x (x^2 + 1) = x^5 + 2x^3 + x\) 。从这里进行使用偶数个球的状态转移后,结果为 \(x^5 + 12x^3 + 12x\)

需要注意的是,从下往上数第 \(1\) 层的最大区间 \([1,7]\) 包含右端点,所以操作次数为奇数也可以。

通过实现上述方法,可以在 \(\mathrm{O}(Q N M \log N \log \left(\frac{N}{M} \right))\) 的时间复杂度内解决该问题。

  • 满分做法

考虑使用偶数个球的状态转移。对于生成函数 \(f(x)\) ,当考虑使用任意个球的情况时,令 \(g(x) = f(x + 1)\) 即可。要实现从这里进行使用偶数个球的状态转移,则令 \(g(x) = \frac{f(x + 1)+f(x - 1)}{2}\) 。不过,这样做时间复杂度并不会改变。

答案是最底层状态转移后的生成函数 \(f(x)\)\(x = 1\) 处的值,即 \(f(1)\) 。因此,对于从下往上数第 \(k\) 层的生成函数,仅需记录 \(f(2 - k),f(3 - k),\cdots,f(k)\) 的值就可以进行状态转移。这样就能将一个区间所包含的信息量控制在 \(\mathrm{O}(M)\) 个。

考虑处理查询操作。由于第 \(k\) 层的区间依赖于第 \(k + 1\) 层的区间,所以在更新时需要从上层的区间开始更新。此时,通过合理处理最大区间,查询操作可以归结为对 \(\mathrm{O}(M)\) 个区间的删除和添加操作。首先,作为预处理,对于满足 \(1 \leq k \leq M\)\(2 - k \leq l \leq k\)\((k,v)\) ,维护一棵线段树来管理从下往上数第 \(k\) 层区间对应的 \(f(v)\)(运算定义为乘法)。

考虑添加操作。当添加第 \(k\) 层的区间 \([l,r]\) 时,先求出第 \(k + 1\) 层线段树中所有 \([l,r]\) 的值,利用 \(g(x) = \frac{f(x + 1)+f(x - 1)}{2}\) 进行状态转移,然后更新第 \(k\) 层的线段树即可。对于删除操作,直接删除第 \(k\) 层线段树中的 \(f(v)\) 就行。因此,每个查询可以在 \(\mathrm{O}(M^2 \log N)\) 的时间复杂度内处理完毕。

通过上述方法,可以在 \(\mathrm{O}((N + Q)M^2 \log N)\) 的时间复杂度内解决这个问题。

posted @ 2025-02-15 15:17  wing_heart  阅读(34)  评论(0)    收藏  举报