我想找出对的数量是一个很大的数字。如果我给出n个数并求出,那么
S(x) < S(y) where S(k) denotes the sum of digits of integer k.
0 <= x < y <= n
结构是i <= n <= 10^250
例如,假设数字是3
,那么有效的对将是(0,1),(0,2),(0,3),(1,2),(1,3)和(2,3),因此它的计数为6。所以答案就来了。为此,我编写了代码:
#!/bin/python3
import sys
from itertools import permutations
def sumofelement(n):
sum = 0
while(n>0):
temp = n%10
sum = sum + temp
n = n//10
return sum
def validpair(x):
x, y = x
if sumofelement(x) < sumofelement(y):
return True
def countPairs(n):
z = [x for x in range(n+1)]
permuation = permutations(z, 2)
count = 0
for i in permuation:
print(i, validpair(i))
if validpair(i):
count += 1
return count%(1000000007)
if __name__ == "__main__":
n = int(input())
result = countPairs(n)
print(result)
但当数字变化很大时,问题就出现了,比如说10^250。我怎么能优化,我试着去搜索,却找不到任何有效的解决方案。在
让我们暂时忽略第二个约束x<;y
然后,一种策略是将所有具有相同位数和的数字集中在一起。例如,如果你的n是
10^250
,那么s.o.d.1000
将恰好发生1983017386182586348981409609496904425087072829264027113757253089553808835917213113938681936684409793628116446312878275672807319027255318921532869897133614537254127444640190990014430819413778762187558412950294708704055125267388491053875845430856889
次,而s.o.d.10
将出现313933899756954150
次。所以这两个s.o.d.s加在一起会产生这些数的乘积,即622536381330141298432969991820256911356499404510841221727177771404498196898219200726905190334516036530761185604472351714146659153338691825580165670694714765688631611013643183449188160088364429780094383087473530152672586062700335444189441183499432858425871184639350
对。在或者稍微少一点自大的数字:n=88,s.o.d.1=10,s.o.d.2=7,我们得到8和8,因此有64对。在
下面的代码使用一个简单的逐位递归关系来实现这个策略(函数
nonsod
)。由于存在大量冗余分支,所以使用缓存。在n=
10^250
(仍然没有执行x<;y)的完整计数是49689518924223997098471223543364330459595831386684873270186194285660874002514005047966357557084650317768560146609913273315351520002512374912739761203458271777707529815027881619901050952541693486379889157466211100495006800815751752605470841565728511141845695222712435837491694221722360852940495211481721723206152092725455942611410225513504242173241811867522974465909681478041570056834016566434386955417360661126555266582980778790541324964301380703686112669669641207272764740986099727604245250714092580
,只需几秒钟的时间来计算。在现在让我们回到约束二:x<;y
我们可以通过分别对x和y的最左边位数进行条件处理来使用无约束代码。如果它们是相同的,我们可以把它们砍掉,然后使用递归。否则,属于x的那个必须更小。切碎后,我们都回到了一个约束问题。只需要额外的“grace”参数。例如,如果x的第一个数字比y的第一个数字小3,那么x的剩余s.o.d.s可能比y的大2倍
这个算法给出了67535的预期结果,10^250仍然是可行的(在我相当普通的笔记本电脑上2分钟)。结果:
25984328769282898156215987070093760297836281753626742070663593024918781683928674045441700800803359016753562494186043552665812224996953995704125243157891603184533274543105499314528302202972742702392476556566583829840036706378670333595223855845665062500914398291514442277659839377773164451943550566697849130769244805996419427202677753063819693113304304818586290078490380143872959635951851910822582661516954316275598690668540412688085631222123413887008350968291853549698946413333342843654709903250347001
注意:这个答案不考虑后面添加到问题中的约束
(x<y)
。并且不接受任何巨大的输入,比如10^250
。建议按要求改进OP代码。在似乎没有必要实际生成这些对。这意味着不存储和操作像
(1000, 900)
这样的元素,而是直接存储和操作它们的位数之和:(1,9)
因此,您可以对现有函数进行以下修改:
测试n=2K
^{pr2}$n=5K时
^{3}$虽然速度快了95%,但似乎变为O(n^2)
所以这里有一个不同的方法:
我们创建一个dict
{ sum_of_digits: occurences }
,然后 做一个倒过来的单子。例如n=10
这将是当我们经过它时,在任何一个节点上,出现次数乘以前一个节点的和就是具有这个数字总和的任何数字对总计数的贡献。可能是O(n)。与我们的实际数据相比,计数器的大小很小。在
测试N=2K
N=67535
预期的输出是有效对的数量,而不是所有有效对的列表。你可以用简单的组合数学来计算这个数,不需要检查所有的可能性。在
对于
n=3
,对的数目将是n=2
的对数+格式为(x,3)
的对数。x可以在<0,n-1>
范围内,并且包含n
元素。在代码可以使用递归或循环或公式,所有这些代码都应该计算相同的数字,公式显然是最快的。在
相关问题 更多 >
编程相关推荐