题解:P3462 [POI2007] ODW-Weights

P3462 题解

Problem

题目链接

大意:有 \(m\) 个砝码,放到 \(n\) 个容器中,每个砝码有重量 \(w_i\),每个容器有 \(v_i\) 的容量,求最多能放下的砝码数量。

同时,对于任意两个砝码,它们的重量成倍数关系。

Solution

这道题最关键的线索是:对于任意两个砝码,它们的重量成倍数关系。 这个条件意味着,尽管砝码的数量可能非常多,但它们的重量种类实际上是非常有限的。具体来说,由于每个砝码的重量都是其他砝码重量的整数倍(或相等),因此最多只有 \(\log_2(10^9) \approx 30\) 种不同的重量级别。这是因为在每个砝码重量都为 \(2^k\)\(k\) 为非负整数)的极端情况下,砝码的种类数才会达到最大。

那么这道题从哪里入手呢?一般,我们都从题目中较小的数据范围入手。只有最多 \(30\) 种砝码,再结合算法标签中的提示,考虑使用进制解决这道题。

我们可以将问题转化为一个“进制拆分”的问题。具体来说,我们可以将每个容器的容量看作是一个由不同重量砝码组成的“数”,而这个“数”的每一位都对应着一种重量的砝码数量。

例如,在样例中,有一个容器的容量是 \(13\),而砝码的重量有 \(2,4,12\) 这几种。我们可以尝试将 \(13\) 拆分成这几种重量的砝码组合。由于 \(13=12+1\),但这里的 \(1\) 无法用给定的砝码表示(因为没有重量为 \(1\) 的砝码,或者即使有也无法单独使用,因为它不满足倍数关系),所以我们可以将其舍去,只考虑 \(12\)。当然,这个例子有些简化,实际中我们需要考虑所有可能的组合。

需要注意的一点是,拆分是从大往小拆,这点等会会说。

可以看到,题目中的容器是相互独立的,但我们进行进制拆分后就不需要单独考虑了。这是因为我们已经将容器的容量拆分为进制了,所以我们每次放砝码只需要在进制的每一位上加减即可,也就不需要单独考虑了。做法是直接将每个容器拆分,然后将拆分后的进制数加起来。

还是样例中,\(13\) 拆分为 \(0,0,1\)\(9\) 拆分为 \(0,2,0\),最后的总容量拆分为 \(0,2,1\)

好,我们现在已经完成了总容量的进制拆分了。现在,我们需要考虑往容器里面放砝码了。考虑贪心策略,显然,从小往大放砝码一定是最优的。但如果一个位置没有了怎么办?借位!向它的高一位借一个 \(1\)。假设高位进制基数为 \(a\),需要借位的基数为 \(b\),那我们就向高位借走一个 \(a\) 容量,在低位就会多 \(a / b\)\(b\) 容量。具体来说,它表现在进制数第 \(k + 1\) 位减 \(1\),在进制数第 \(k\) 位加 \(a/b\)。如过 \(k + 1\) 位借不了怎么办?借 \(k + 2\) 位。\(k + 2\) 不行就 \(k + 3\),一直到最高位,如果最高位都借不了那也就说明我们再也放不了砝码了。

好了,这就做完了,借位部分写一个 DFS 就行,具体实现参考代码。

代码:Link

posted @ 2024-10-29 07:30  Eliauk_FP  阅读(12)  评论(1编辑  收藏  举报