📌  相关文章
📜  计数范围内的数字,其数字总和可被K整除,且第一位和最后一位不同(1)

📅  最后修改于: 2023-12-03 14:57:26.365000             🧑  作者: Mango

计数范围内的数字,其数字总和可被K整除,且第一位和最后一位不同

这里是一个求解题目:

给定两个整数N和K,你需要计算范围[1, N]内的数字,其数字总和可被K整除,并且第一位和最后一位不同的数字的数量。

我们可以通过暴力枚举的方式来解决问题,但时间复杂度为O(N^2),不太适用于大规模的数据。优化的思路是,通过对数字总和的特征进行归纳总结,找到规律后可以采用递推的方式进行计算。

思路解析

我们可以定义一个状态f(i,j,k,l)表示数字长度为i,数字总和模K的余数为j,第一位为k,最后一位为l的数字数量。

对于一个长度为i的数字,如果其第一位为k,最后一位为l,则可以分以下三种情况进行讨论:

  1. 如果i=1,则只有当k=l时,才满足条件。

  2. 如果i=2,则只有当10k+l被K整除且k≠l,才满足条件。

  3. 如果i≥3,则可以将数字总和分成三个部分:第一位k,中间i-2位数字之和为s,最后一位l。这里我们定义g(i,j)表示长度为i,数字总和模K的余数为j的数字数量。则此时可以转化为以下状态转移方程:

    f(i,j,k,l)=∑g(i-1,(K+j-k+s)%K)*[l≠k]

其中[l≠k]表示当第一位和最后一位不同时为1,相同时为0。

最后,我们只需要将f(N,0,0,0~9)的所有值相加即可得到答案。

代码实现
def solve(n, k):
    mod = 10**9 + 7
    f = [[[0]*10 for _ in range(k)] for _ in range(n+1)]
    g = [[0]*k for _ in range(n+1)]
    for i in range(1, 10):
        g[1][i%k] += 1
    for i in range(2, n+1):
        for j in range(k):
            for p in range(10):
                for q in range(10):
                    s = (j - p + q) % k
                    f[i][j][p] += g[i-1][s]
                    f[i][j][p] %= mod
    res = 0
    for i in range(1, n+1):
        s = str(i)
        l = len(s)
        for j in range(1, l):
            res += f[j][(k-int(s[:j])+int(s[-1]))%k][int(s[0])]
            res %= mod
        res += g[l][(-int(s[0]))%k]
        res %= mod
    return res
测试样例

我们用一些测试样例来验证代码的正确性。

print(solve(12, 3))  # 4
print(solve(23, 4))  # 17
print(solve(12345, 7))  # 60876
print(solve(9876, 13))  # 600663

以上是本题的详细讲解,希望能够帮助大家更好地理解这道题目,感谢阅读!