How to find the smallest number with just 0 and 1 which is divided by a given number?

14,832

Solution 1

The question equals to using 10i mod n (for each i, it can be used at most once) to get a sum m of n. It's like a knapsack problem or subset sum problem. In this way, dynamic programming will do the task.

In dynamic programming the complexity is O(k*n). k is the number of digits in answer. For n<105, this code works perfectly.

Code:

#include <stdio.h>
#define NUM 2000

int main(int argc, char* argv[])
{
    signed long pow[NUM],val[NUM],x,num,ten;
    int i,j,count;
    for(num=2; num<NUM; num++)
    {
        for(i=0; i<NUM; pow[i++]=0);
        count=0;
        for(ten=1,x=1; x<NUM; x++)
        {
            val[x]=ten;

            for(j=0; j<NUM; j++)if(pow[j]&&!pow[(j+ten)%num]&&pow[j]!=x)pow[(j+ten)%num]=x;
            if(!pow[ten])pow[ten]=x;
            ten=(10*ten)%num;
            if(pow[0])break;
        }

        x=num;
        printf("%ld\tdivides\t",x=num);
        if(pow[0])
        {
            while(x)
            {
                while(--count>pow[x%num]-1)printf("0");
                count=pow[x%num]-1;
                printf("1");
                x=(num+x-val[pow[x%num]])%num;
            }
            while(count-->0)printf("0");
        }
        printf("\n");
    }
}

PS: This sequence in OEIS.

Solution 2

There's an O(n)-time (arithmetic operations mod n, really) solution, which is more efficient than the answer currently accepted. The idea is to construct a graph on vertices 0..n-1 where vertex i has connections to (i*10)%n and (i*10+1)%n, then use breadth-first search to find the lexicographically least path from 1 to 0.

def smallest(n):
    parents = {}
    queue = [(1 % n, 1, None)]
    i = 0
    while i < len(queue):
        residue, digit, parent = queue[i]
        i += 1
        if residue in parents:
            continue
        if residue == 0:
            answer = []
            while True:
                answer.append(str(digit))
                if parent is None:
                    answer.reverse()
                    return ''.join(answer)
                digit, parent = parents[parent]
        parents[residue] = (digit, parent)
        for digit in (0, 1):
            queue.append(((residue * 10 + digit) % n, digit, residue))
    return None

Solution 3

I think this is a fair and interesting question.

Please note that though what you describe is a proof there always exist such number, the found number will not always be minimal.

Only solution I can think of is to compute the remainders of the powers of 10 modulus the given n and than try to construct a sum giving remainder 0 modulo n using at most one of each of these powers. You will never need more than n different powers(which you prove i your question).

Solution 4

Here is a readable solution using BFS in java. The approach is similar to David's with some improvements.

You build a decision tree of whether to append a 0 or 1 and perform BFS to find the lowest such valid multiple of the input number.

This solution also leverages modulo (of the input number) to compute really large results. Full description available in the comments in the code.

You can also access the same code snippet in ideone.

import java.util.ArrayDeque;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Queue;
import java.util.Scanner;
import java.util.Set;

public class Main {
    // Return the smallest multiple of the number (as a string) consisting only of digits 0 and 1
    //
    // All possible digits that can be constructed using the digits 0/1 can be represented
    // as a tree, where at each level, appending a 0 is one branch and appending a 1 is another
    //
    // If we perform BFS on this tree, the first number we see which is an exact multiple of the input
    // number will be the result (since it will be the smallest). Make sure to consider left
    // branch (i.e. 0) before considering the right branch (i.e. 1)
    //
    // The 2 paths we take at each level when the current number is num:
    //      (num * 10)
    //      (num * 10) + 1
    // 
    // Since the result can grow huge quite easily, it might not be possible to store the result in a
    // 32 or even a 64 bit int/long variable.
    //
    // One alternative is to use BigNumber, but a simpler alternative exists if we leverage modulo.
    //
    // The operations we perform above (i.e. multiplications and additions) will retain the useful part
    // of the result when using modulo. We use the given number itself as the modulo, and when we see a
    // result of 0, it means we have found a number which is an exact multiple of the input number.
    //
    // To reconstruct the number, we need to store the parent nodes of each node, when adding the node
    // in the queue (similar to using BFS for computing shortest path)
    //
    // We will also need to know if we appended a 0 or a 1 at each step, and so we add this information
    // as part of the node data structure as well.
    //
    // Re-visiting nodes is unecessary since we have seen this modulo result (i.e. value % num) already.
    // Any additional digits we add from now will only make the number longer and we already are tracking
    // the path for this same modulo result we've seen earlier.
    //
    public static String multiple(int num) {
        if (num < 0) {
            throw new IllegalArgumentException("Invalid args");
        }

        String result = "0";

        if (num > 0) {
            // An array to mark all the visited nodes
            boolean[] isVisited = new boolean[num];
            Arrays.fill(isVisited, false);

            // The queue used by BFS
            Queue<Node> queue = new ArrayDeque<>();

            // Add the first number 1 and mark it visited
            queue.add(new Node(true, 1 % num, null));
            isVisited[1 % num] = true;

            // The final destination node which represents the answer
            Node destNode = null;

            while (!queue.isEmpty()) {
                // Get the next node from the queue
                Node currNode = queue.remove();

                if (currNode.val == 0) {
                    // We have reached a valid multiple of num
                    destNode = currNode;
                    break;
                } else {
                    // Visit the next 2 neighbors
                    // Append 0 - (currNode.val * 10)
                    // Append 1 - (currNode.val * 10) + 1

                    // Append a '0'
                    int val1 = (currNode.val * 10) % num;
                    if (!isVisited[val1]) {
                        queue.add(new Node(false, val1, currNode));
                        isVisited[val1] = true;
                    }

                    // Append a '1'
                    int val2 = (val1 + 1) % num;
                    if (!isVisited[val2]) {
                        queue.add(new Node(true, val2, currNode));
                        isVisited[val2] = true;
                    }
                }
            }

            // Trace the path from destination to source
            if (destNode == null) {
                throw new IllegalStateException("Result should not be null");
            } else {
                StringBuilder reverseResultBuilder = new StringBuilder();
                Node currNode = destNode;
                while (currNode != null) {
                    reverseResultBuilder.append(currNode.isDigitOne ? '1' : '0');
                    currNode = currNode.parent;
                }
                result = reverseResultBuilder.reverse().toString();
            }
        }

        return result;
    }

    // Node represents every digit being appended in the decision tree
    private static class Node {
        // True if '1', false otherwise (i.e. '0')
        public final boolean isDigitOne;
        // The number represented in the tree modulo the input number
        public final int val;
        // The parent node in the tree
        public final Node parent;

        public Node(boolean isDigitOne, int val, Node parent) {
            this.isDigitOne = isDigitOne;
            this.val = val;
            this.parent = parent;
        }
    }

    public static void main(String[] args) {
        int num = new Scanner(System.in).nextInt();
        System.out.println("Input number: " + num);
        System.out.println("Smallest multiple using only 0s and 1s as digits: " + Main.multiple(num));
    }
}

Solution 5

This is a fast way to get the first 792 answers. Def the most simple code:

__author__ = 'robert'

from itertools import product

def get_nums(max_length):
    assert max_length < 21 #Otherwise there will be over 2 million possibilities
    for length in range(1, max_length + 1):
        for prod in product("10", repeat=length):
            if prod[0] == '1':
                yield int("".join(prod))

print list(get_nums(4))
[1, 11, 10, 111, 110, 101, 100, 1111, 1110, 1101, 1100, 1011, 1010, 1001, 1000]

nums = sorted(get_nums(20))
print len(nums)

solution = {}

operations = 0

for factor in range(1, 1000):
    for num in nums:
        operations += 1
        if num % factor == 0:
            solution[factor] = num
            break
    print factor, operations
    if factor not in solution:
        print "no solution for factor %s" % factor
        break

print solution[787]

max_v = max(solution.values())
for factor, val in solution.items():
    if val == max_v:
        print factor, max_v


[1, 11, 10, 111, 110, 101, 100, 1111, 1110, 1101, 1100, 1011, 1010, 1001, 1000]
1048575
1 1
2 3
3 10
4 14
5 16
6 30
7 39
8 47
9 558
10 560
11 563
12 591
13 600
14 618
15 632
16 648
17 677
18 1699
19 1724
20 1728
..
..
187 319781
188 319857
..
..
791 4899691
792 5948266
no solution for factor 792
10110001111
396 11111111111111111100
Share:
14,832
Sayakiss
Author by

Sayakiss

I thought you'd never see my profile.

Updated on June 05, 2022

Comments

  • Sayakiss
    Sayakiss about 2 years

    Every positive integer divide some number whose representation (base 10) contains only zeroes and ones.

    One can prove that:

    Consider the numbers 1, 11, 111, 1111, etc. up to 111... 1, where the last number has n+1 digits. Call these numbers m1, m2, ... , mn+1. Each has a remainder when divided by n, and two of these remainders must be the same. Because there are n+1 of them but only n values a remainder can take. This is an application of the famous and useful “pigeonhole principle”;

    Suppose the two numbers with the same remainder are mi and mj , with i < j. Now subtract the smaller from the larger. The resulting number, mi−mj, consisting of j - i ones followed by i zeroes, must be a multiple of n.

    But how to find the smallest answer? and effciently?