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