题解 CF413D
机房同学借“理解题意”之名在模拟赛时打了很久的 2048。在此表示严厉谴责。
考虑怎么存储状态。进行模拟,每次入栈的元素可能为 \(2\) 或 \(4\)。
- 如果入栈的元素为 \(2\) 的话,可以证明(模拟)能够一直合并。
- 但如果入栈元素为 \(4\) 的话且栈顶为 \(2\),\(2\) 和其以前的元素就再也无法继续合并了。但如果栈顶不为 \(2\) 仍可以合并。
因此我们只需要储存 最后一个可合并的单调递减序列。来看两个实例如下:
128 | 32 | 8 | 4 | 2 |
---|
- 此时如果入栈为 \(2\),最终合并结果为 \(\{ 128, 32, 16 \}\)。
- 此时如果入栈为 \(4\),最终合并结果为 \(\{ 128, 32, 8, 4, 2, 4 \}\),前面的部分已经不可合并,故只需存储 \(\{ 4 \}\)。
128 | 32 | 16 | 8 | 4 |
---|
- 此时如果入栈为 \(2\),结果为 \(\{ 128, 32, 16, 8, 4, 2 \}\),依旧可以合并。
- 此时如果入栈为 \(4\),最终合并结果为 \(\{ 128, 64 \}\)。
由于是单减序列,又注意到 \(k \leq 11\),可以想到用状压来存储。
定义状态:\( \text{dp}[i][s] \) 表示前 \(i\) 个元素,栈内状态为 \(s\) 的方案数。
- 初始状态:\( \text{dp}[0][0] = 1 \)
- 状态转移略复杂,大致思路如下:
- 插入 \(2\):可以一直合并(单调序列加深)
- 插入 \(4\):若栈顶为 \(2\) 则阻断,重新开始一个新段;否则也能继续合并
Code
1 | const int N = 2e3 + 10; |
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来源 House Tsumugi!
评论