0413 独子数
* * * *
拉格朗日计划
* * * *
独子数

若一个d位正整数的所有子串中有且只有一个能被d整除,就称其为独子数。

例如,5671的所有子串分别是5, 6, 7, 1, 56, 67, 71, 567, 671和5671,其中只有56能够被4整除,因此5671是独子数。

类似的,104是独子数,因为只有子串0能够被3整除。1132451也是独子数,因为只有子串245能够被7整除。

记$F(N)$是小于N的独子数的数量。可以验证$F(10)=9, F(10^3)=389, F(10^7)=277674$。

求$F(10^{19})$。

本题难度:



解答

动态规划递推计算,记录每一种状态$(a,b,c)$的数字串总数。

其中a,b都是N位二进制数,交表示模d以及d-1余r的数是否出现过,c记录是否已经有过能整除d的子串。

从左到右依次添加数位并更新状态即可,最终结果是$3079418648040719$。

注:因用到walrus算符,以下代码为Python 3。

from collections import defaultdict

r=0
for n in range(1,20):
    d=defaultdict(int)
    for i in range(1,10):
        d[(1 << (i%n),0,i%n==0)]+=1
    for i in range(n-1):
        d,d2=defaultdict(int),d
        for a,b,c in d2:
            for j in range(10):
                a2=b2=0
                c2=c
                for k in range(n):
                    if x:=(k==0)+((a & (1 << k))!=0)+((b & (1 << k))!=0):
                        z=(k*10+j)%n
                        if z==0:
                            if c2+x>1:
                                break
                            c2=True
                        if (a2 & (1 << z)) or x>1:
                            b2|=1 << z
                        a2|=1 << z
                else:
                    d[a2,b2,c2]+=d2[a,b,c]
    print("n=",n,"completed")
    r+=sum(d[(a,b,c)] for a,b,c in d if c)

print(r)