13

I am given a number k in the range 1 to 10000. The problem is to find the smallest multiple that can be written only with the digit 1 (known as a repunit). So for k=3 the solution is 111 because 3 divides 111, but 3 does not divide 1 or 11. For k=7, the solution is 111111 (six ones).

How to calculate the solution for any k?

I understand I need to use remainders since the solution can be very big (or I suppose use a BigInteger class)

Colonel Panic
  • 132,665
  • 89
  • 401
  • 465
Lucian Tarna
  • 1,806
  • 4
  • 25
  • 48

3 Answers3

14

This problem involves a bit of math, so let's start with it.

1111...1 (n digits one) =

enter image description here.

Let's denote our random number with k. Since our condition is

enter image description here,

it follows that

enter image description here

or

enter image description here,

where enter image description here denotes congruence operator. We are searching for the smallest such n, which is exactly a multiplicative order. Multiplicative order exists if and only if 10 and 9k are relatively prime, which is easy to check. One example of effectively calculating multiplicative order can be found here, and if you don't need an optimized version, then the basic modular exponentiation would do the trick:

int modexp(long mod) // mod = 9*k
{            
    int counter = 1;
    long result = 10;            
    while(result != 1)
    {
        result = (result * 10) % mod;
        counter++;
    }

    return counter;
}

Bonus: this function is guaranteed to run at most phi(mod) times, where phi(mod) is Euler totient function. Important properties of this function are that phi(mod) < mod, and that multiplicative order divides phi(mod).

Miljen Mikic
  • 14,765
  • 8
  • 58
  • 66
  • Since OP hinted at using BigInteger, modexp from the Java Library can be used: http://docs.oracle.com/javase/7/docs/api/java/math/BigInteger.html#modPow(java.math.BigInteger,%20java.math.BigInteger) – henje Jul 14 '15 at 21:42
  • @henje Yes, in case that OP wants to use BigInteger class, then he can use modexp directly like you mentioned. – Miljen Mikic Jul 15 '15 at 08:53
  • I'm trying to solve this problem only using algebra but I m stuck on trying to isolate n from other variable on the expression 10^n (congruence operator) 1 (mod 9*k) – ArthurQ Sep 23 '17 at 03:53
  • @Nacho You can calculate Euler totient function of `9k`, find its divisors and sort them in ascending order. First divisor that satisfies given congruence relation is your solution. – Miljen Mikic Sep 23 '17 at 08:32
10

If you're always guaranteed a solution (at least for even n and multiples of 5, there is no solution. I haven't given it much thought for others, but I think the rest should always have a solution):

(a + b) % c = ((a % c) + (b % c)) % c
(a * b) % c = ((a % c) * (b % c)) % c

Where % is the modulo operator: a % b = the remainder of the division of a by b. This means that we can take modulos between additions and multiplications, which will help solve this problem.

Using this, you can use the following algorithm, which is linear in the number of digits of the result and uses O(1) memory:

number_of_ones = 1
remainder = 1 % n
while remainder != 0:
  ++number_of_ones

  # here we add another 1 to the result,
  # but we only store the result's value mod n.
  # When this is 0, that is our solution.
  remainder = (remainder * 10 + 1) % n

print 1 number_of_ones times

Followup question: what if you can use 0 and 1?

IVlad
  • 43,099
  • 13
  • 111
  • 179
  • Omg you are so right. This was so easy if I had observed that you can take the former remainder multiply by 10 and add 1 and modulo n would be the remainder of that former number * 10 + 1... I feel kinda bad. – Lucian Tarna Jul 14 '15 at 19:16
  • To answer your question if I can use both 1 and 0 I will have to use this programe and determine remainders until I find 2 equal remainders modulo n. (for the numbers of form 11111.... ) . Let's call the numbers I have found x and y. Then the answer I am looking for is y - x (with y greater than x). Such a number will always be found because of pigeonhole principle . Or common sense as I like to say. We have max n remainders and an infinity of 11111... numbers. So I will find 2 numbers that have the same remainder. Their difference is composed of 0s and 1s. Thank you for the Followup question! – Lucian Tarna Jul 14 '15 at 19:19
  • I like Followup questions :P . And it is very good having the same style . Who knows maybe this exam I will receive a question like that . Very nice! – Lucian Tarna Jul 14 '15 at 19:20
  • @LucianTarna not exactly true for the followup. You can also have something like `1010110` as the smallest. You need to use a breadth first search for this, and look at the problem as a graph. This current problem can also be seen as a linked list graph where you only add another `1` node. The new problem will be a tree where you add a `1` branch and a `0` branch at each step. – IVlad Jul 14 '15 at 19:51
  • Ohhhh I see what you mean. This was really tricky :P hehe. Nice one ! – Lucian Tarna Jul 14 '15 at 19:59
  • So instead of memorizing all these numbers I just keep a graph. And I keep adding to it and making a breadth first to check the numbers until I find a solution. This seems to take A LOT OF time – Lucian Tarna Jul 14 '15 at 20:03
  • @LucianTarna you don't keep an actual graph, just a FIFO queue in which you store remainders. Constructing the actual solution is a little tricky, but doable with some extra information stored. – IVlad Jul 14 '15 at 20:47
  • I see. Thank you very much! :P – Lucian Tarna Jul 15 '15 at 05:10
3

An implementation of IVlad's idea:

public static String multiple (int n){
    String result = "No Solution";
    if (n > 3 && n % 2 != 0 && n % 5 != 0){
        StringBuilder sb = new StringBuilder("11");
        int k = 11;
        int remain = 11 % n;
        while (remain != 0){
            remain = (remain*10 + 1)%n;
            sb.append('1');
        }
        result = sb.toString();
    }
    return result;
}

public static void main(String[] args) {
    Random rand = new Random();
    for (int i = 0; i < 100; i++) {
        int n = 2 + rand.nextInt(9998);
        System.out.println(n+": "+multiple(n));
    }   
}
Community
  • 1
  • 1
David Pérez Cabrera
  • 4,960
  • 2
  • 23
  • 37