CF div2 1035 D(逆向思维 + dp)
D
最近的一场CF div2的D题,个人认为这道题题意晦涩难懂,难度非常大,蒟蒻也是想了将近整整一天才弄明白了一点点qwq。。。
先回顾一下题意:\([1,n]\) 共 \(n\) 个位置按顺序排列,每个位置有一个 \(token\)。共有 \(n\) 次取 \(token\) 的操作,其中第 \(i\) 次可以取第 \([a_{i},i]\) 个 \(token\) 中的任意一个(\(a_{i}\in [0,i]\))。特殊地,当 \(a_{i}=0\) 时,此次操作不能取任何 \(token\);否则一定会取走对应区间内的某一个存在的 \(token\)。可见 \(n\) 次操作可构成的 \(n\) 个区间序列个数为 \((n + 1)!\)(显然,证明略)。每一种区间序列对应的不同的取 \(token\) 序列个数记作 \(f(a)\)(两个 取 \(token\) 序列 不同,当且仅当存在第 \(t\) 次操作,取走的 \(token\) 种类不同(或没取,也算作一个不同的种类)),求这 \((n + 1)!\) 种区间序列的 \(f(a)\) 之和模给定模数 \(m\) 的值。(之后才明白为什么没有给定模数:如果给定了模数,那么答案就至多有 \(5000\) 种,这样就存在通过打表暴算来 \(AC\) 本题的可能。)
求一个给定区间序列的 \(f(a)\) 本身就是一件十分困难的事情。而本题并不是让求给定 \((a_{1},a_{2},...,a_{n})\) 的 \(f(a)\) 的值,而是让求所有可能的序列 \(a\) 的 \(f(a)\) 之和。其实这样我们就可以逆向思考:本题答案可以等价于求:所有可能的 取 \(token\) 序列 的 \((a_{1},a_{2},...,a_{n})\) 数量之和。因为某个区间序列 \((a_{1},a_{2},...,a_{n})\) 与 某个取 \(token\) 序列可以建立起一一映射的关系,因此正难则反,考虑如何解决转化后的题意:
由于第 \(i\) 个 \(token\) 只可能被第 \([i\backsim n]\) 个区间取得,因此可以考虑从后往前 \(dp\):
\(dp[i][j]\):考虑 \(token[i \backsim n]\),从第 \(i\) 个 \(token\) 开始往后取,恰好有 \(j\) 个 \(token\) 被取走,所有可能的 \(token\) 序列对应的 \((a_{1},a_{2},...,a_{n})\) 数量之和。(第二维的定义蒟蒻无法弄明白为什么要这样定义,怎样才能在下次遇到同类型题目时想到这样定义。。。希望有大佬能来指导我!!!)
决策第 \(i\) 个 \(token\) 的情况:
- 不取第 \(i\) 个 \(token\):此时完全等价于 \(a_{i}=0\),从第 \(i + 1\) 个 \(token\) 开始取恰好 \(j\) 个 \(token\),对应 \(dp[i + 1][j]\),直接转移过来即可:
- 取第 \(i\) 个 \(token\):也是本题最难理解的转移部分。显然 \(dp[i][j]\) 应当从 \(dp[i + 1][j - 1]\) 转移而来。此时应该这样考虑:在心中钦定好某一个 取 \(token[i+1,n]\) 序列,该序列会对应多个 \((a_{i+1},...,a_{n})\) 区间序列。现在要在开头添加一个 \(token[i]\),使得序列变为 \((a_{i},...,a_{n})\)。由于前面恰好取走了 \(j-1\) 个 \(token\),故第\([i+1 \backsim n]\) 区间内已经用掉了 \(j - 1\) 个区间,因此此时还剩下 \((n-i+1)-(j-1)\) 个区间可以取走第 \(i\) 个 \(token\)(给 \(token[i]\) 分配的区间数目,即 \(a_{i}\) 中 \(i\) 的取值个数);且这些区间对应的 \(a_{k}\) 取值均为 \(1,2,...,i\) 共 \(i\) 种取值(即每个 \(a_{i}\) 的取值个数均为 \(i\)),则每个 取 \(token\) 序列对应的区间序列数量会变为之前的 \((n-i+1-(j-1))*i\) 倍。因此转移为:
两个转移合起来进行即可。最终根据状态定义,答案为:
具体细节见代码。

浙公网安备 33010602011771号