📅  最后修改于: 2023-12-03 14:57:26.365000             🧑  作者: Mango
这里是一个求解题目:
给定两个整数N和K,你需要计算范围[1, N]内的数字,其数字总和可被K整除,并且第一位和最后一位不同的数字的数量。
我们可以通过暴力枚举的方式来解决问题,但时间复杂度为O(N^2),不太适用于大规模的数据。优化的思路是,通过对数字总和的特征进行归纳总结,找到规律后可以采用递推的方式进行计算。
我们可以定义一个状态f(i,j,k,l)
表示数字长度为i,数字总和模K的余数为j,第一位为k,最后一位为l的数字数量。
对于一个长度为i的数字,如果其第一位为k,最后一位为l,则可以分以下三种情况进行讨论:
如果i=1,则只有当k=l时,才满足条件。
如果i=2,则只有当10k+l被K整除且k≠l,才满足条件。
如果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
以上是本题的详细讲解,希望能够帮助大家更好地理解这道题目,感谢阅读!