E. Staircases
注意一下 \(n,m \leq 1e3\),\(q \leq 1e4\),因此 \(O(nq)\) 的做法也是可以的。
初始状态的答案可以用 \(dp\) 在 \(O(nm)\) 内求出:
状态定义:\(dp_{i,j,0/1}\):考虑以 \((i, j)\) 结尾的楼梯,\(0/1\) 表示横着/竖着结尾,方案数。
状态转移:\(dp_{i,j,0} \leftarrow dp_{i,j-1,1} + 1,dp_{i,j,1} \leftarrow dp_{i-1,j,0} + 1\)
对于每次修改,会影响到的格子状态的数量仅为 \(O(n+m)\) 级别,因此每次翻转后暴力修改可能会影响到的格子即可,总复杂度 \(O((n+m)*q)\)。
注意每个单格子都会被重复计数一次,因此每次计算的答案还需要额外减掉当前空闲格子的数量。
code
F. RBS
求的是 \(n\) 个字符串的所有排列中的 ... 的最大值,\(n \leq 20\),显然考虑状压 \(dp\)。
将左括号当作 \(1\),右括号当作 \(-1\),求该括号串的前缀和 \(pre\)。那么一个括号串是 \(RBS\),当且仅当:
- 末尾项 \(pre\) 等于 \(0\)
- 前缀所有位置的 \(pre \geq 0\)
因此 \(dp\) 状态除了对 \(RBS\) 前缀最大数量的定义,还要保证整个前缀的合法性,即只有拼接形成的串的所有前缀值非负时,才可以用于后续的 \(dp\) 转移。
注意,从已计算完的状态 \(state_{a}\) 转移新的状态 \(state_{b}\),若在结尾拼接新串后产生了前缀值为负的前缀,则新的状态不能用于后续的转移,但答案是仍然可以更新的,在 code 中充分地体现了这一点的处理。
而状态转移部分就相对简单些了:因为已知状态无论按何种顺序拼接,只要合法,最终的前缀值就是固定的,可以直接预处理得到。那么, 在结尾添加一个新串是否可行 与 此次添加对答案的贡献\(\space\) 就可以二分快速得到(这里不再赘述具体怎样实现的,看官解就行,讲得很清晰)
总复杂度 \(O(2^{n}*n*\log A)\),\(A\) 最大为 \(4e5\),为单个字符串的最长长度。
这道题让我体会到了 \(dp\) 的灵活性。在想状态转移时,一定要追根溯源,从定义和本质的角度出发去分析,而不是死板地根据经验去套公式。
code