Reputation: 129
So, I have a homework like this:
Given two number n
and k
that can reach the long long
limit, we do such operation:
n = n / k
if n
is divisible by k
n
by 1
if n
is not divisible by k
Find the smallest number of operations to go from n
to 0
.
This is my solution
#define ll long long
ll smallestSteps(ll n, ll k) {
int steps = 0;
if (n < k) return n;
else if (n == k) return 2;
else {
while (n != 0) {
if (n % k == 0) {
n /= k;
steps++;
}
else {
n--;
steps++;
}
}
return (ll)steps;
}
}
This solution is O(n/k)
I think?
But I think that n
and k
could be extremely big, and thus the program could exceed the time limit of 1s. Is there any better way to do this?
Edit 1: I use ll
for it to be shorter
Upvotes: 0
Views: 395
Reputation: 77860
This can be done with an even simpler main program.
Convert n
to base k
. Let d
be the number of digits in this number.
To get to 0, you will divide by k
(d-1)
times.
The number of times you subtract 1
is the digital sum of this number.
For instance, consider n=314, k=3.
314 in base 3 is 102122
. This has 6 digits; the digital sum is 8.
You will have 6-1+8 steps ... 13 steps to 0.
Use your C++ packages to convert to the new base, convert the digits to integers, and do the array sum. This pushes all the shift-count work into module methods.
Granted this won't work for weird values of k
, but you can also steal available conversion packages instead of writing your own.
Upvotes: 1
Reputation: 19213
The algorithm can be improved given these observations:
n<k
then k|(n-m)
will never hold for any positive m. So the answer is n
steps.(k|n)
does not hold then the biggest number m, m<n
for which it does is n - (n%k)
. So it takes n%k
steps until (k|m) holds again.Actually all that you need is to keep doing division with remainder using std::div
(or rely on compiler to optimize) and increase steps by remainder+1.
steps=0
while(n>0)
mod = n%k
n = n/k
steps+=mod + 1
return steps
Upvotes: 8