C++11, many bytes, very fast, wow (1.5 s on 1999999998, 0.2 s on 1…10000)
(Golfed Python version below.)
We start with a concept somewhat similar to aditsu’s solution, where we inductively build up a collection of modular remainders reachable in n steps. But instead of waiting until we find remainder 0, we check for two found remainders a and b such that a·10^n + b = 0. This meet-in-the-middle approach halves the depth of the search tree, so it’s much faster on large inputs and uses much less memory.
Some benchmarks:
$ echo 99999999 | \time ./decbin 1111111122222222333333334444444455555555666666667777777788888889 0.18user 0.01system 0:00.20elapsed 99%CPU (0avgtext+0avgdata 69360maxresident)k 0inputs+0outputs (0major+16276minor)pagefaults 0swaps $ echo 999999999 | \time ./decbin 111111111222222222333333333444444444555555555666666666777777777888888889 1.22user 0.04system 0:01.27elapsed 100%CPU (0avgtext+0avgdata 434776maxresident)k 0inputs+0outputs (0major+37308minor)pagefaults 0swaps $ echo 2147483647 | \time ./decbin 4661316525084584315813 0.00user 0.00system 0:00.01elapsed 72%CPU (0avgtext+0avgdata 5960maxresident)k 0inputs+0outputs (0major+1084minor)pagefaults 0swaps $ echo 1999999998 | \time ./decbin 555555556111111111666666667222222222777777778333333333888888889444444445 1.42user 0.08system 0:01.50elapsed 100%CPU (0avgtext+0avgdata 544140maxresident)k 0inputs+0outputs (0major+38379minor)pagefaults 0swaps $ \time ./decbin 10000.out 0.19user 0.00system 0:00.20elapsed 100%CPU (0avgtext+0avgdata 3324maxresident)k 0inputs+264outputs (0major+160minor)pagefaults 0swaps
Code:
#include <algorithm> #include <boost/iterator/transform_iterator.hpp> #include <fstream> #include <list> #include <iostream> #include <string> #include <utility> #include <vector> using namespace boost; using namespace std; static inline bool cmp_first_partnered(pair<int, pair<int, int>> a, pair<int, pair<int, int>> b) { return a.first < b.first; } static inline bool eq_first_partnered(pair<int, pair<int, int>> a, pair<int, pair<int, int>> b) { return a.first == b.first; } static pair<int, int> retrace(int modulus, int place, pair<int, int> state, list<vector<int>>::iterator i, list<vector<int>>::iterator j, string &ret) { if (i == j) return state; state = retrace(modulus, (place * 10LL) % modulus, state, next(i), j, ret); int remainder = state.first; long long k = state.second * 10LL; if (!binary_search(i->cbegin(), i->cend(), remainder)) { remainder = ((long long)remainder + modulus - place) % modulus; k += 1; } int digit = k / modulus; if (digit != 0 || ret.size()) ret += '0' + digit; return make_pair(remainder, k % modulus); } static void mult(int modulus, int x, int y, vector<pair<int, pair<int, int>>>::iterator i, vector<pair<int, pair<int, int>>>::iterator j) { if (y - x == 1) { for (auto k = i; k != j; k++) k->first = (k->first * 10LL) % modulus; return; } int z = (x + y) / 2; vector<pair<int, pair<int, int>>>::iterator k = lower_bound( i, j, make_pair(int(((long long)modulus * z + 9) / 10), make_pair(0, 0))); mult(modulus, x, z, i, k); mult(modulus, z, y, k, j); inplace_merge(i, k, j, [](pair<int, pair<int, int>> a, pair<int, pair<int, int>> b) { return make_pair(a.first, a.second.second) < make_pair(b.first, b.second.second); }); } static string go(int modulus) { if (modulus == 1) return "1"; int sequence = 1; list<vector<int>> v = {{0}}; vector<pair<int, pair<int, int>>> partnered; int place = 1; while (true) { v.emplace_back(v.rbegin()->size() * 2); vector<int> &previous = *next(v.rbegin()), ¤t = *v.rbegin(); auto offset = [modulus, place, sequence](int a) { return (a + (long long)place) % modulus; }; auto old_mid = lower_bound(previous.cbegin(), previous.cend(), modulus - place), new_mid = lower_bound(previous.cbegin(), previous.cend(), place); current.resize( set_union(new_mid, previous.cend(), make_transform_iterator(previous.cbegin(), offset), make_transform_iterator(old_mid, offset), set_union(previous.cbegin(), new_mid, make_transform_iterator(old_mid, offset), make_transform_iterator(previous.cend(), offset), current.begin())) - current.begin()); int place2 = modulus - (long long)place * place % modulus; auto offset_partnered = [modulus, place, place2, sequence](pair<int, pair<int, int>> a) { return make_pair((a.first + (long long)place2) % modulus, make_pair((a.second.first + (long long)place) % modulus, sequence + a.second.second)); }; auto old_mid_partnered = lower_bound(partnered.cbegin(), partnered.cend(), make_pair(modulus - place2, make_pair(0, 0))), new_mid_partnered = lower_bound(partnered.cbegin(), partnered.cend(), make_pair(place2, make_pair(0, 0))); vector<pair<int, pair<int, int>>> next_partnered(partnered.size() * 2 + 1); auto i = set_union(partnered.cbegin(), new_mid_partnered, make_transform_iterator(old_mid_partnered, offset_partnered), make_transform_iterator(partnered.cend(), offset_partnered), next_partnered.begin(), cmp_first_partnered); if (new_mid_partnered == partnered.cend() || new_mid_partnered->first != place2) *i++ = make_pair(place2, make_pair(place, sequence)); next_partnered.resize( set_union(new_mid_partnered, partnered.cend(), make_transform_iterator(partnered.cbegin(), offset_partnered), make_transform_iterator(old_mid_partnered, offset_partnered), i, cmp_first_partnered) - next_partnered.begin()); partnered.swap(next_partnered); sequence += previous.size(); place = (place * 10LL) % modulus; mult(modulus, 0, 10, partnered.begin(), partnered.end()); partnered.resize( unique(partnered.begin(), partnered.end(), eq_first_partnered) - partnered.begin()); auto with_first = [](int a) { return make_pair(a, make_pair(a, 0)); }; vector<pair<int, pair<int, int>>> hits; set_intersection(partnered.cbegin(), partnered.cend(), make_transform_iterator(current.cbegin(), with_first), make_transform_iterator(current.cend(), with_first), back_inserter(hits), cmp_first_partnered); if (hits.size()) { pair<int, pair<int, int>> best = *min_element( hits.begin(), hits.end(), [](pair<int, pair<int, int>> a, pair<int, pair<int, int>> b) { return a.second.second < b.second.second; }); string ret = ""; pair<int, int> state = retrace(modulus, 1, make_pair(best.second.first, 0), v.begin(), prev(v.end()), ret); retrace(modulus, 1, make_pair(best.first, state.second), v.begin(), prev(v.end()), ret); return ret; } } } int main(int argc, const char *argv[]) { ios_base::sync_with_stdio(false); if (argc >= 2) { ofstream ofs(argv[1]); for (int modulus = 1; modulus <= 10000; modulus++) ofs << go(modulus) << '\n'; } else { int modulus; cin >> modulus; cout << go(modulus) << '\n'; } return 0; }
Python, 280 bytes (8.6 seconds on 1999999998 with PyPy)
n=input() if n<2:print 1;exit() d={0:0} l=[] k=1 b=x=y=0 while 1: for a in[0]+l: m=(a+k)%n if m not in d:l.append(m);d[m]=b k=(k*10)%n;b+=1 for a in l: if(-k*a)%n in d: while(a-x)%n:x+=10**d[(a-x)%n] while(-y-k*a)%n:y+=10**d[(-y-k*a)%n] print(10**b*x+y)/n;exit()