Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to find divisor to maximise remainder?

Tags:

c++

algorithm

Given two numbers n and k, find x, 1 <= x <= k that maximises the remainder n % x.

For example, n = 20 and k = 10 the solution is x = 7 because the remainder 20 % 7 = 6 is maximum.


My solution to this is :

int n, k;
cin >> n >> k;
int max = 0;
for(int i = 1; i <= k; ++i)
{
  int xx = n - (n / i) * i; // or int xx = n % i;
  if(max < xx)
    max = xx;
}
cout << max << endl;

But my solution is O(k). Is there any more efficient solution to this?

like image 275
0x6773 Avatar asked Oct 12 '15 18:10

0x6773


People also ask

What is the maximum possible remainder?

The maximum size of the remainder in any division problem is the maximum divisor minus 1. If we are talking about a 16 bit unsigned divisor, it's maximum value is 65535 or ((2^16)-1). This would imply that the maximum remainder is 65534.

Can we get remainder greater than divisor?

Properties of Remainder: The remainder is always less than the divisor. If the remainder is greater than the divisor, it means that the division is incomplete. It can be greater than or lesser than the quotient.

Can remainder and quotient be equal?

Explanation: When 8 is divided by 3 and 7, it returns the same Quotient and Remainder.

How do you find the remainder of a number?

First, if a number is being divided by 10, then the remainder is just the last digit of that number. Similarly, if a number is being divided by 9, add each of the digits to each other until you are left with one number (e.g., 1164 becomes 12 which in turn becomes 3), which is the remainder.


2 Answers

Not asymptotically faster, but faster, simply by going backwards and stopping when you know that you cannot do better.

Assume k is less than n (otherwise just output k).

int max = 0;
for(int i = k; i > 0 ; --i)
{
  int xx = n - (n / i) * i; // or int xx = n % i;
  if(max < xx)
    max = xx;
  if (i < max)
    break;   // all remaining values will be smaller than max, so break out!
}
cout << max << endl;

(This can be further improved by doing the for loop as long as i > max, thus eliminating one conditional statement, but I wrote it this way to make it more obvious)

Also, check Garey and Johnson's Computers and Intractability book to make sure this is not NP-Complete (I am sure I remember some problem in that book that looks a lot like this). I'd do that before investing too much effort on trying to come up with better solutions.

like image 72
TheGreatContini Avatar answered Sep 29 '22 08:09

TheGreatContini


This problem is equivalent to finding maximum of function f(x)=n%x in given range. Let's see how this function looks like:

f(x)=n%x

It is obvious that we could get the maximum sooner if we start with x=k and then decrease x while it makes any sense (until x=max+1). Also this diagram shows that for x larger than sqrt(n) we don't need to decrease x sequentially. Instead we could jump immediately to preceding local maximum.

int maxmod(const int n, int k)
{
    int max = 0;

    while (k > max + 1 && k > 4.0 * std::sqrt(n))
    {
        max = std::max(max, n % k);
        k = std::min(k - 1, 1 + n / (1 + n / k));
    }

    for (; k > max + 1; --k)
        max = std::max(max, n % k);

    return max;
}

Magic constant 4.0 allows to improve performance by decreasing number of iterations of the first (expensive) loop.

Worst case time complexity could be estimated as O(min(k, sqrt(n))). But for large enough k this estimation is probably too pessimistic: we could find maximum much sooner, and if k is significantly greater than sqrt(n) we need only 1 or 2 iterations to find it.

I did some tests to determine how many iterations are needed in the worst case for different values of n:

    n        max.iterations (both/loop1/loop2)
10^1..10^2    11   2   11
10^2..10^3    20   3   20
10^3..10^4    42   5   42
10^4..10^5    94  11   94
10^5..10^6   196  23  196
up to 10^7   379  43  379
up to 10^8   722  83  722
up to 10^9  1269 157 1269

Growth rate is noticeably better than O(sqrt(n)).

like image 23
Evgeny Kluev Avatar answered Sep 29 '22 07:09

Evgeny Kluev