蓝桥杯系列 - 2018国赛 - 调手表

博客探讨了一道涉及动态规划的编程题目,描述了如何通过状态转移方程解决数字跳跃问题,初始状态设置的难点以及优化策略。文章还提供了Python代码实现,并针对超时问题进行了优化。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

很明显的动态规划,设置 dp[n],dp[i] 表示调到数字 i 所需的最少步数。这道题的状态转移方程很简单:
dp[i] = min(dp[i - 1], dp[(i - k) % n]) + 1
不过,这道题难的地方就在于,dp 的初始化比较难想到,有一点比较细。正确的初始化方案如下:

//0 位置开始, 逐次往后跳 1for i in [0, n - 1]:  
	dp[i] = i

// 从 k 位置开始, 逐次往后跳 k 步, 根据数学关系可推导出最多跳 n * k / gcd(n, k) 
// 步就可以覆盖 [0, n - 1]所有数字
step = 1  // 记录步数
temp = k  // 记录位置
for i in [0, n * k / gcd(n, k)]:  
	dp[i] = min(dp[i], step)
	temp = (temp + k) % n
	step += 1

然而,这么做还是不行,会超时,因为如果 n, k 互质,n * k / gcd(n, k) 相当于 n * k,这个数字可能会非常大。
解决的方案也很简单,我们可以知道最终 dp[i] 最大不会超过 n - 1,也就是说任意一个数字最多只需 n - 1 步就可以到达。因此,将第二部的初始化代码修改如下:

for i in [0, min(n - 1, n * k / gcd(n, k)]:
	dp[i] = min(dp[i], step)
	temp = (temp + k) % n
	step += 1

Python 代码如下:

import sys


def gcd(x, y):
    if x > y:
        x, y =y, x
    r = y % x
    while r:
        x, y = r, x
        r = y % x
    return x


n, k = list(map(int, sys.stdin.readline().strip().split()))
dp = [_ for _ in range(n)]
step, temp = 1, k
for i in range(min(n, n * k // gcd(k, n))):
    dp[temp] = min(dp[temp], step)
    step += 1
    temp = (temp + k) % n
for i in range(n):
    dp[i] = min(dp[i], dp[i - 1] + 1, dp[i - k] + 1)
print(max(dp))

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值