题目描述
给出两个整数 a,b,每次操作可以把 a 变成 a+1 或 a∗k 。求把 a 变成 b 至少需要几步操作。
输入
第一行三个数 a,b,k。(0≤a,b,k≤1018)
输出
输出最少操作次数。
样例输入
2 10 2
样例输出
3
数据规模与约定
时间限制:1 s
内存限制:256 M
100% 的数据保证 0≤a,b,k≤1e18
这道题第一眼的思路很容易想到:直接暴力广搜,但显然,数据量这么大,会超时。这里主要介绍贪心解法。
首先我们要了解一个基础知识,就是关于进制。对于一个n进制数而言,用它再乘上n,相当于在其末尾加上了一个0,理解的话,类比十进制就好,当然这也很好想通。那么我们可以这样想,对于两个数a,b,我们把它想象成题目里给的k进制,举个例子:a:12345,b:123456780,以上分别是两个数字的k进制形式。那么我们可以想了,怎么样才能最快地从a到b呢?我这里直接给出答案:a先乘上k,变成123450,然后再加6,也就是123456,继续重复上述操作:1234560,1234567,12345670,12345678,123456780,如此,我们便在六步之内完成操作。其他方案一定会比这样慢,可以自行验证。
当然,这道题的难点主要在于如何去转化这个思路成代码,不过上面的思路没有相关经验也很难想到就是了。先来总结一下我们上述的思路:例如我们现在有1432 和 12,都是k进制数,我们的转变是这样的:14,140,143,1430,1432,其实我们可以总结出:当当前的数字完全等于我们所要的数字的某个前缀的时候,我们将之乘上k是最优方法。当然也可能出现已经大于前缀的情况,例如1432和24, 这里就只能将24加到132然后再去乘k了。否则的话我们可以想一想,24乘两次k就会大于1432,乘一次k的话,剩下的就只能不断地去加了。其他情况也全都比这个要次数多。
接下来介绍我们的贪心方程:
当a<=b:ans+=1+b%k,b/=k;当a>b:ans+=b-a,并结束循环。
解释一下。第一个方程的意思实际上是:前面那个1代表乘一次,后面那个b%k代表咱们每次乘之前所需要加上的值,举例就是,1430*5+2=1432 14*5+3=143,以上就是两次1+b%k操作。然后最后的b-a,对应的就是12+2=14的操作。所以这其实和上面我们一开始说的操作顺序是相反的。
当然,上述式子有些难以理解的话,也可以直接硬做,也就是都转换成k进制再按我们之前的方法做。这样比较好理解,也比较容易想到,就是写起来略显麻烦。