兔兔 的 题解 —— From Hero to Zero

From Hero to Zero


题目描述

有一天,小明给了你两个数字 n n n k k k
现在,你需要对数字 n n n 进行一下操作:
对于每一步操作,你可以选择下面其中一个项目:

  1. 将的 n n n 值减少 1 1 1
  2. 如果能 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 27262524876210 (不一定是最优的哦~)
请你计算出数字 n n n 变为 0 0 0 时最少需要的操作数。

输入格式

第一行输入一个整数 t t t ( 1 ≤ t ≤ 100 ) (1 \leq t \leq 100) (1t100),表示数据个数
接下来 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}) (1n1018,2k1018)

输出格式

将数字 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 59585719186210
对于第二组数据,可以连续除以 18 18 18 0 0 0 使变为 1 1 1


分析

这道题最容易想到的就是模拟了。
代码如下:

#include 

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 n1,这样的时间复杂度是 q q q,不妨优化一下:
我们可以直接 n − q n - q nq,这样时间复杂度是 1 1 1。相比时间复杂度是 q q q 的,就快了很多。


正解代码如下:

#include 

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;
}


你可能感兴趣的:(模拟,循环结构)