From Hero to Zero
题目描述
有一天,小明给了你两个数字 n n n 和 k k k。
现在,你需要对数字 n n n 进行一下操作:
对于每一步操作,你可以选择下面其中一个项目:
- 将的 n n n 值减少 1 1 1
- 如果能 n n n 被 k k k 整除,可以使 n / k n / k n/k
比如 n = 27 , k = 3 n = 27, k = 3 n=27,k=3 时:你可以进行下列操作: 27 → 26 → 25 → 24 → 8 → 7 → 6 → 2 → 1 → 0 27 \rightarrow 26 \rightarrow 25 \rightarrow 24 \rightarrow 8 \rightarrow 7 \rightarrow 6 \rightarrow 2 \rightarrow 1 \rightarrow 0 27→26→25→24→8→7→6→2→1→0 (不一定是最优的哦~)
请你计算出数字 n n n 变为 0 0 0 时最少需要的操作数。
输入格式
第一行输入一个整数 t t t ( 1 ≤ t ≤ 100 ) (1 \leq t \leq 100) (1≤t≤100),表示数据个数
接下来 t t t 行,每行 2 2 2 个整数 n n n 和 k k k ( 1 ≤ n ≤ 1 0 18 , 2 ≤ k ≤ 1 0 18 ) (1 \leq n \leq 10^{18}, 2 \leq k \leq 10^{18}) (1≤n≤1018,2≤k≤1018)
输出格式
将数字 n n n 变为 0 0 0 的最小次数
样例
样例输入
2
59 3
1000000000000000000 10样例输出
8
19样例解释
对于第一组数据,有: 59 → 58 → 57 → 19 → 18 → 6 → 2 → 1 → 0 59 \rightarrow 58 \rightarrow 57 \rightarrow 19 \rightarrow 18 \rightarrow 6 \rightarrow 2 \rightarrow 1 \rightarrow 0 59→58→57→19→18→6→2→1→0
对于第二组数据,可以连续除以 18 18 18 个 0 0 0 使变为 1 1 1。
分析
这道题最容易想到的就是模拟了。
代码如下:
#include <cstdio>
int T;
long long N, K;
long long ans;
int main()
{
scanf("%d", &T);
for (int i = 1; i <= T; i++)
{
scanf("%lld %lld", &N, &K);
ans = 0;
while (N)
{
if (N % K == 0) N /= K;
else --N;
++ans;
}
printf("%lld\n", ans);
}
return 0;
}
但是这道题用模拟是会超时的,我们需要进一步优化。
当
n
=
p
k
+
q
n = pk + q
n=pk+q 时,我们需要循环
q
q
q 次
n
−
1
n - 1
n−1,这样的时间复杂度是
q
q
q,不妨优化一下:
我们可以直接
n
−
q
n - q
n−q,这样时间复杂度是
1
1
1。相比时间复杂度是
q
q
q 的,就快了很多。
正解代码如下:
#include <cstdio>
int T;
long long N, K;
long long ans;
int main()
{
scanf("%d", &T);
for (int i = 1; i <= T; i++)
{
scanf("%lld %lld", &N, &K);
ans = 0;
while (N)
{
if (N % K == 0) ++ans, N /= K;
else ans += N % K, N -= N % K;
}
printf("%lld\n", ans);
}
return 0;
}