对于任何非负整数K,假设我们正好有两个值为2 ^ K的硬币(即2的K次幂)。
现在我们给了一个很长的N.我们需要找到不同方式的数量,我们可以用我们拥有的硬币来表示N值。
(如果在表示中出现不同次数的值,则认为两个表示不同。)
示例:设N = 6然后回答为3,因为在这种情况下可能有以下三种表示形式:
{1, 1, 2, 2}
{1, 1, 4} and
{2, 4}
如果N可以达到10 ^ 18,该如何做?
答案 0 :(得分:0)
我们可以从简单的解决方案开始,我们有一个2
,其余1
。这当然要求N
至少为3.否则,没有解决方案:
coins1 = N - 2
coins2 = 1
nSolutions = 1
让我们首先讨论找到M
等硬币的可能合并操作的数量的任务,其中必须合并每个硬币(即,仅使用单个硬币类型)。这是M
到2
的可能整数除法数。此过程可以缓存中间结果以更快地执行后续调用(请参阅动态编程)。
但这有用吗?在当前状态下,我们现在可以随后为一个1's
交换两个2
。这可以完成,直到不再有两个1's
,总共floor(N/2 - 1)
次。在每次合并之后(实际上在每次合并之后就足够了),我们必须检查所有2's
可以合并的频率。该州仍有1's
,因此我们无法使用其他类型的硬币:
while(coins1 >= 3)
{
coins1 -= 2;
coins2 += 1;
nSolutions += 1;
nSolutions += findNumberOfMerges(coins2); //this could be improved
}
如果剩下while
,则剩下一个或两个1's
。如果剩下一个,我们就完成了,因为这个必须始终存在,我们已经检查了所有可能的组合,以不同的方式表示2's
。
if(coins1 == 1)
return nSolutions;
在另一种情况下,我们可以再次合并。但是,这不会导致有效状态,因为没有第二种硬币类型。但我们可以再次合并以获得有效状态(一个4
(变为coins2
),其余2's
(变为coins1
)):
coins1 = coins2 + 1 - 2;
coins2 = 1;
nSolutions += 1;
现在我们的状态与开头类似,因此我们可以再次运行整个过程。并且一次又一次,直到它返回。