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

后端 未结 11 1284
情话喂你
情话喂你 2020-11-29 22:44

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,

相关标签:
11条回答
  • 2020-11-29 23:23

    Here's a brute force version in Raku:

    say (1..Inf).map( *.base(2) ).first( * %% $n );
    

    The code generates a lazy (potentially infinite) sequence of candidate numbers and then searches for the first element that's divisible by n.

    Being brute force it's not exceptionally fast, but the code is striking in its simplicity and expressiveness, as it is typical for Raku.

    0 讨论(0)
  • 2020-11-29 23:25

    Here is a C# solution using linked list

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    using System.Collections;
    
    namespace ConsoleApplication1
    {
        class Program
        {
            public static void print(LinkedList<int> lst)
            {
                foreach(int i in lst)
                {
                    Console.Write(i);
                }
            }
    
            static void Main(string[] args)
            {
                int number = Convert.ToInt32(Console.ReadLine());
                int product;
                LinkedList<int> list = new LinkedList<int>();
                bool Istrue = true;
                int range = 1;
    
                while (range <= 10) { 
                    Istrue = true;
                    product = number * range;
                    while (product > 0)
                    {
                        list.AddFirst(product % 10);
                        product /= 10;
    
                    }
    
                    foreach (int i in list)
                    {
                        if (i > 1) Istrue = false;
                    }
    
                    if (Istrue) { print(list); break; }
                    else
                    {
                        list.Clear();   
                    }
    
                    range++;    
                }
    
                Console.WriteLine("Done");
    
                string s = Console.ReadLine();
            }
        }
    }
    
    0 讨论(0)
  • 2020-11-29 23:27

    Nice question. I use BFS to solve this question with meet-in-the-middle and some other prunings. Now my code can solve n<109 in a reasonable time.

    #include <cstdio>
    #include <cstring>
    
    class BIT {
    private: int x[40000000];
    public:
        void clear() {memset(x, 0, sizeof(x));}
        void setz(int p, int z) {x[p>>5]=z?(x[p>>5]|(1<<(p&31))):(x[p>>5]&~(1<<(p&31)));}
        int bit(int p) {return x[p>>5]>>(p&31)&1;}
    } bp, bq;
    
    class UNIT {
    private: int x[3];
    public: int len, sum;
        void setz(int z) {x[len>>5]=z?(x[len>>5]|(1<<(len&31))):(x[len>>5]&~(1<<(len&31)));}
        int bit(int p) {return x[p>>5]>>(p&31)&1;}
    } u;
    
    class MYQUEUE {
    private: UNIT x[5000000]; int h, t;
    public:
        void clear() {h = t = 0;}
        bool empty() {return h == t;}
        UNIT front() {return x[h];}
        void pop() {h = (h + 1) % 5000000;}
        void push(UNIT tp) {x[t] = tp; t = (t + 1) % 5000000;}
    } p, q;
    
    int n, md[100];
    
    void bfs()
    {
        for (int i = 0, tp = 1; i < 200; i++) tp = 10LL * (md[i] = tp) % n;
    
        u.len = -1; u.sum = 0; q.clear(); q.push(u); bq.clear();
        while (1)
        {
            u = q.front(); if (u.len >= 40) break; q.pop();
            u.len++; u.setz(0); q.push(u);
            u.setz(1); u.sum = (u.sum + md[u.len]) % n;
            if (!bq.bit(u.sum)) {bq.setz(u.sum, 1); q.push(u);}
            if (!u.sum) {
                for (int k = u.len; k >= 0; k--) printf("%d", u.bit(k));
                puts(""); return;
            }
        }
    
        u.len = 40; u.sum = 0; p.clear(); p.push(u); bp.clear();
        while (1)
        {
            u = p.front(); p.pop();
            u.len++; u.setz(0); p.push(u);
            u.setz(1); u.sum = (u.sum + md[u.len]) % n;
            if (!bp.bit(u.sum)) {bp.setz(u.sum, 1); p.push(u);}
            int bf = (n - u.sum) % n;
            if (bq.bit(bf)) {
                for (int k = u.len; k > 40; k--) printf("%d", u.bit(k));
                while (!q.empty())
                {
                    u = q.front(); if (u.sum == bf) break; q.pop();
                }
                for (int k = 40; k >= 0; k--) printf("%d", u.bit(k));
                puts(""); return;
            }
        }
    }
    
    int main(void)
    {
        // 0 < n < 10^9
        while (~scanf("%d", &n)) bfs();
        return 0;
    }
    
    0 讨论(0)
  • 2020-11-29 23:28

    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
    
    0 讨论(0)
  • 2020-11-29 23:32

    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).

    0 讨论(0)
提交回复
热议问题