【题解】【数位DP】P4798 卡尔文球锦标赛
本文最后更新于:2024年1月16日 晚上 18:54
[CEOI2015 Day1] 卡尔文球锦标赛
题目描述
译自 CEOI2015 Day1 T2「Calvinball championship」
一场卡尔文球比赛会有 \(n\) 名选手参与,他们的编号分别为 \(1\dots n\),分为若干个非空的球队。我们规定球队之间按照每个球队编号最小的选手的编号排序,并且以从 1 开始的连续整数编号。
举个栗子,譬如 1 号选手自己成一队,2, 3 和 5 号选手成一队,4 和 6 号选手成一队。
> \(\ \texttt{1}\)
> \(\ \texttt{2 3 5}\)
> \(\ \texttt{4 6}\)
那么 1 号选手的球队就是 1 号球队,2 号选手的球队就是 2 号球队,4 号选手的球队就是 3 号球队。
> \(\ \texttt{1|1}\)
> \(\ \texttt{2|2 3 5}\)
> \(\ \texttt{3|4 6}\)
每个人每天会选择不同的球队,我们可以在记录时省略选手的编号,仅记录每个位置对应选手所属球队编号的序列(上述例子为
1 2 2 3 2 3
),因为每天的选手是一样的。当可能的选择方案全部被使用过后,锦标赛就结束了。
由于选择方案十分多,选择困难症患者纷纷表示力不从心。今年,我们决定根据记录的序列的字典序来选择方案。因此,第一天,所有人都在一个队
1 1 1 1 1
;第二天,所有人都与 6 号针锋相对
1 1 1 1 1 2
……在最后一天,所有人互相打响战争
1 2 3 4 5 6
。
对于给定的球队记录,请你算出将会在未来的哪一天使用该记录。输出这个数字对 \(1\ 000\ 007\) 取余的结果。
输入格式
第一行,一个正整数 \(n(1 \leq n \leq 10\ 000)\)。
第二行,\(n\) 个以空格分隔的正整数,表示任务所给的球队记录。
输出格式
输出一个正整数,表示任务所给的球队记录将会被使用的天数对 \(1\ 000\ 007\) 取余的结果。第一天的天数为 1。
样例 #1
样例输入 #1
1 |
|
样例输出 #1
1 |
|
提示
请注意,三人比赛中可能的选择有 1 1 1
1 1 2
1 2 1
1 2 2
和 1 2 3
。
数据范围与提示
数据点 | \(1-3\) | \(4-5\) | \(6-7\) | \(8-10\) |
---|---|---|---|---|
\(n\le\) | \(14\) | \(100\) | \(1\ 000\) | \(10\ 000\) |
时间限制 1.00s
内存限制 62.50MB
题解
把每个人的球队编号看作是一个数位,搜索满足要求的所有数。因此,我们可以用数位 DP 来解决这个问题。
66分题解:记忆化搜索的数位DP
用递归很快就能写出来,但是肯定会爆MLE。
思路和数位DP模板的一样,也有 \(limit\) 来指示当前位是否有上限。
\(dp[pos][preMax]\) 表示当前位为 \(pos\),前pos位(包括当前的第pos位)的最大值为 \(preMax\) 的方案数。这个是没有 \(limit\) 的。
1 |
|
100分题解:使用迭代的数位DP + 自滚动数组优化空间
我们可以先写一个迭代的版本,然后再进行优化。
通过对 \(dp[pos][preMax]\) 的分析,我们可以发现它有 \(preMax+1\) 个子节点。
所有子情况,如图所示:
\(dp[pos+1][preMax]\) 图中节点的所有的左子节点(包括中间的子节点)
\(dp[pos+1][preMax+1]\) 图中节点的最右边的子节点
转移方程为:
\[dp[pos][preMax] = dp[pos+1][preMax] \times preMax + dp[pos+1][preMax+1]\]
我们再来看看数值受到上界限制的情况,
每个 \(limited\) 为真的节点,其子节点可以分为两类:
\(dp[pos+1][preMax+1]\)
\(limited[pos+1]\)
如图所示,对于受限制的节点,其方案数递推方程为:
\[limited[pos]=dp[pos+1][preMax]\times (A[pos+1]-1) + limited[pos+1]\]
根据 \(limited[pos]\) 和 \(dp[pos][preMax]\) 的递推方程,我们可以写出迭代的版本:
1 |
|
这样做空间复杂度为 \(O(n^2)\),显然超出了内存限制。所以用滚动数组优化一下。
这也是为什么我们要先写迭代版本,因为dfs必须要用到 \(dp[pos][preMax]\) 的所有值,所以无法优化空间。(或许用bfs可以优化?)
下是最终的滚动数组优化版本,非常简洁。
时间复杂度为 \(O(n^2)\),空间复杂度为 \(O(n)\)。
1 |
|
效率非常好,时间 384ms,内存 680KB。全场最快好吧。 :D
