给定2个整数l和r,计算[l,r]中满足这些约束的数量
1)该数字应该可被7整除
2)该号码至少包含三位数7
3)该数字包含的数字7比数字4更多
777,774746符合这些限制条件,7771,77,747474不符合。
使用暴力可以很容易地找到答案,但是当范围非常大时,可能需要很长时间。
我认为动态编程可以帮助解决这个问题,但我想不出解决方案
有人可以给我一些指导吗?
答案 0 :(得分:2)
取自最初的暴力版本:
Iterate with i over numbers between [l,r]
Use modulo to check if i is divisible by 7
Use modulo and division to get counts of digits in i
digit_count(7) >= 3
digit_count(7) > digit_count(4)
这是我提出的一些想法......
这个很简单。我们可以将其改进为仅使用可被i
整除的7
。如果我给你一个号码x
并要求你生成我可以被n
整除的号码,直到你达到y
,那么你最好这样做:
for (auto i = x + x % n; i < y; i += n)
因此,对于7
和l
之间r
的倍数的情况,您需要做的就是运行循环for (auto i = l + l % 7; i < r; i += 7)
这将为您提供7倍的加速来自蛮力版本。
没有必要执行多个分区和模数来获取您经历的每个数字的位数。既然你知道你增加了多少,你也知道什么数字改变了什么。这样,您只需要将起始编号分成数字(例如l % 7 + l
)。
现在我们要存储的不是数字的数量,而是实际上非常类似BCD的数字 - 一个数字数组,代表我们当前正在使用的数字。然后,您会收到类似std::vector<int>
[7, 7, 2, 4, 5, 7]
数字772457
的数字[7, 7, 2, 4, 5, 7] + 6 = [7, 7, 2, 4, 6, 3]
。现在你需要做的就是每次增加循环计数器时在数组内使用BCD算法,转到int
。
我们需要存储的另一件事是两个sevens
s - fours
和sevens
。在初始化阶段,一旦你解体了#34;数据中的第一个数字,您只需浏览它,并为每个7
增加fours
,为4
fours
增加4
。而且您只需保持这些数字是最新的:每次更新数组时,您为每个4
减去7
,并为每个sevens
增加sevens
你在数组中创建的。对于数字fours
也是如此。然后,您可以比较r
&gt; = 3&amp;&amp; | range | numbers f/ c2 | c2_groups | c2_total | c1_total |
| 0 - 1k | 777 | 1 | 1 | ~143 |
| 1k - 10k | _777, 7_77, 77_7, 777_ | 4 | 40 | ~1286 |
| 10k - 100k | __777, _7_77, ... | 10 | 1000 | ~12857 |
&gt; numbers f/ c2
并快速了解结果。
有趣的是,这使得你没有理论在复杂性方面的改进,它可能无法工作,但我怀疑它应该......它有很多代码,所以我和#39;我不打算提供它。您可能最终使用倒置的BCD阵列或从迭代范围的c2_groups
结束开始,因此您不需要调整阵列的大小。也许你可以提出更多的改进和调整。但是,我强烈怀疑解决方案可以通过这种方式逐渐减少复杂性。
现在这根本不是动态编程。或者是吗?如果你考虑一下,我有一种直觉,认为这个数字数组作为BCD的想法现在可以转换成一个问题,你可以在这里查找包含给定组合的排列。您可以从中制作图表并进行搜索。这就是你动态的地方。但是,我担心这会导致相当长的事情......
但是我已经对此有了第一个疑问,那就是7的可分性检查,然后将其应用于图中找到的所有数字(图表仅支持标准2和3)它的性质和产量包含组合的所有数字)。所以最后,它归结为算法应该支持的范围大小,以及满足第一个标准的数字比率和满足这些范围中第二个和第三个标准的数字。
修改强> 我后来发现我计算符合标准的数字的想法是不正确的。一些小比较表:
cx_total
如果increment [1, 0, 7, _] -> [1, 0, 8, _]
^ ^
是符合条件2的数字,则[0, p, _, _]
是数字中任意数字和7s的可能组合数,[0, 0, p, _]
是符合范围内标准x的数字总数
考虑到这一点,看起来首先按数字位数过滤是否有效是一件非常值得怀疑的事。我想这需要一些比实施解决方案需要更长时间的数学分析......
空间搜索
具有等效于方法#2的状态,可以在数字范围内进行DFS。它将基于可移动的偏移量而不是递增7,而是存储数字向量并在其中增加值,例如
p
这是算法将在核心循环中执行的操作。然后,您可以检查当前数字向量设置是否符合标准 - 例如push [7, 7, _, _] -> [7, 7, 0, _]
^ ^
可以实现它们,而int
则不能(pop [7, 7, 7, 9] -> [7, 7, 7, _]
^ ^
是指向的元素)。这样,您将继续增加最高位数,跳过大量数字。每次有可能满足要求时,您将增加偏移并重复该过程:
increment
一旦你处于最不重要的数字位置,你也将开始检查每个候选人7的可分性。您可以尝试将数字转换为[7, 7, 8, _]
并使用模数或使用某种可分解算法(这些使用数字以便“巧合”)。
这样,您将获得一个通过所有条件的数字并将其返回。现在你可能会遇到一个耗尽给定数字范围内所有数字的情况。在这种情况下,您需要将偏移量移回一个位置:
push
现在,您使用0
,看到1
符合条件,2
可以再次使用7
。然后浏览7787
,7
,r
,...序列,直至到r
,看到{{1}}符合第2和第3条件但{{1}}失败了。等等...
您还需要检查自己是否已超过{{1}}限制。我想这可以通过将{{1}}拆分为数字并将其与最高位数进行比较,以非常合理的方式完成。
鉴于我们没有对此进行数学分析,并且这仍然经历了相当多的数字(特别是在7是最不重要的数字的情况下),我想知道这是否真的值得实施。但它也不是超级复杂的东西。祝你好运!
答案 1 :(得分:1)
1:if(yourint % 7 == 0)
对于2:检查此链接split int into digits,检查数字是否等于7并计入3。
对于3:消费链接2与if
数字等于7或4比计数器++
最后你应该检查你的柜台(7和4)哪一个是最高的。