12.2 CW 模拟赛 T3. 四舍五入
算法
考虑如何判定 \(x\) 能否变成 \(y\)
从低位到高位逐位比较, 若它们当前位相同, 则不进行进位, 否则只有当 \(y\) 这一位为 \(0\) 或 \(1\) 时才可能有解
具体原因为对 \(x\) 当前位四舍五入后, 该位会变成 \(0\) , 变成 \(0\) 以后, 前面的位如果进位, 那么当前位会变成 \(1\) , 显然一个位置不可能进位 $ \geq 2$ 次, 因此只能得到 \(0, 1\) 两种值中的一种
显然的, 我们考虑数位 \(\rm{dp}\)
首先我们考虑状态的设计, 根据上文提到的性质, 我们令 \(f_{i, 0 / 1 / 2}\) 表示考虑了从低位到高位第 \(i\) 位数字, 其中前一位不进位 / 一定进位 / 可进位可不进位的方案数
注意到状态转移时, 我们需要考虑 \(z\) 的限制, 具体的, 分类讨论 \(z\) 当前位置上的数字, 由上可知一定为 \(0, 1\) 或者与当前位相同无需进位
显然的, 状态转移的难点在于需要进位时的方案数, 考虑分类讨论
边界条件 \(f_{len + 1, 0 / 1 / 2} = 1\) 仅当搜出来的数 \(\leq x\) , 注意在这道题中, 前导 \(0\) 不影响答案
答案即为 \(f_{1, 0}\)
时间复杂度 \(\Theta (\omega T \lg V)\) , 其中 \(V\) 为值域, \(\omega = 10\)
简单复习, 属于比较好的数位 \(\rm{dp}\) 思维题
四舍五入解的性质
考虑 \(y\) 作为 \(x\) 的四舍五入解, 也就是 \(y\) 可以通过若干次四舍五入变成 \(x\) 时, \(y, x\) 之间的关系
首先观察到, 一次四舍五入操作, 相当于把自己清 \(0\) 之后是否向上进位 \(1\)
那么我们这样考虑, 枚举 \(i : [1, len]\)
- 如果 \(x_i = y_i\) 成立, 那么不进行操作
- 否则
- 若 \(x\) 这一位不为 \(0/1\) , 那么显然无解
- 其他情况需要考虑前一位能否进位
所以我们可以记录之前的进位情况, 然后才能处理
后面的数位 \(\rm{dp}\) 同样利用了这些性质
求出种类数
我们现在要构造 \([0, x]\) 区间中, 能通过若干次四舍五入变成 \(z\) 的 \(y\) 的个数
不难想到数位 \(\rm{dp}\)
我们从低位到高位处理, 这样才方便处理进位, 这是与传统数位 \(\rm{dp}\) 不同的地方
你可能想问: 这种情况下如何处理 \(limit\) , 我们如何知道怎样才能不超出范围限制
其实和普通的限制是一样的, 你思考只要出现了当前位置比 \(x\) 的当前位置大或小的数, 对高位就一定有/没有约束, 只有相等的情况下, 才会继承之前的约束
到最后如果约束成立返回 \(1\) , 否则返回 \(0\) , 记忆化搜索会解决一切效率问题
这样子我们可以构造合法解了:
- \(z\) 的这一位为 \(0/1\)
根据进位条件推当前的进位情况, 当前数字枚举可得 - 否则只能和 \(z\) 这一位数字相同
根据进位条件反推当前的数字
总结
善于归纳性质, 注意数位 \(\rm{dp}\) 的特殊实现方式
数位 \(\rm{dp}\) 有两种实现方式, 具体的:
- 从高位往低位推, 使用 \(limit\) 标记
- 从低位往高位推, 使用递推的大小比较
附: 感谢 \(\rm{qcz}\) 大佬让我最终搞懂了这个题, 也明白了数位 \(\rm{dp}\) 的一些性质
代码是抄袭借鉴的 \(\rm{qcz}\) 大佬, 不放了
操作类问题一定要先把操作的方式搞清楚


浙公网安备 33010602011771号