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()
6It should always be solvable. Clearly there must exist at least one q such that there are an infinite number of n such that 10^n mod x = q. Take x such values of n and add together the respective powers 10^n. – feersum – 2015-10-15T21:57:52.777
1Multiples of 9 seem to produce unusually high results. – SuperJedi224 – 2015-10-16T02:02:48.507
1Related Project Euler problem, for anyone else who thought this question looked familiar – Sp3000 – 2015-10-16T02:42:45.830
1By polynomial complexity, do you mean polynomial in the number of digits of the input, or polynomial in the value of the input? – Reto Koradi – 2015-10-16T03:48:17.190
1@RetoKoradi Polynomial in the number of digits, of course! Otherwise, you cannot run it => no fun. – anatolyg – 2015-10-16T07:19:05.997
input();print 0- you should probably limityto > 0 ;) – jazzpi – 2015-10-16T12:32:54.317@SuperJedi224 well, you need at least 9
1's to get a multiple of 9 – aditsu quit because SE is EVIL – 2015-10-16T13:38:10.633I guess I was too optimistic about complexity, and it's impossible to make it polynomial on the size of input - the size of the output seems to be exponential on input. But hey - all the 16 answers so far are brute-force?! Surely you can do better! – anatolyg – 2015-10-16T15:51:45.060
Umm... there is always a value that can be resolved that looks like binary (circumventing the output 0 rule), simply because there is an infinite range of numbers. – Addison Crump – 2015-10-16T16:08:03.573
3@anatolyg mine is not brute force – aditsu quit because SE is EVIL – 2015-10-16T16:29:33.307
@primo re bounty: time to calc or time to print in console? Maybe redirect to file – edc65 – 2015-10-20T16:15:48.320
@edc65 Output must be generated, although for timing it will be discarded (i.e. piped to
/dev/null. I will however check it for accuracy). You may optimize your solution to produce each value sequentially, if that helps. If you prefer to be timed with a specific interpreter/compiler, please specify. – primo – 2015-10-20T16:21:45.2401@primo, how special-cased can the fast code be? E.g. can it restrict to using narrower int types which wouldn't be sufficient for input
99999999? – Peter Taylor – 2015-10-26T13:40:29.900@PeterTaylor if it produces the correct output for all values between 1-10000, I will consider it valid. I will be evaluating all solutions shortly. – primo – 2015-10-27T11:23:46.050
I've a proof that the length of the output is indeed at most linear in the size of the input (and thus exponential in the length of the input), but it cannot fit in a comment box. It relies on two ideas: 1) That for any N, 10^i % N has a period with length <= N - 1 or has finite support, and 2) There exists a multiple of N that equals a linear combination of numbers less than N such that their coefficients sum to at most N. – Candles – 2015-10-28T08:27:17.047
The Bounty was awarded to aditsu's c answer. Final scoreboard: http://codepad.org/DVRGITHP (average of 5 runs). I didn't test any "count by one" solutions, so if I've missed yours, and it's faster than aditsu's c, I'll double down on the bounty.
– primo – 2015-10-28T09:54:32.737I'm like 95% certain that the length of the output is linear in the length of the input; I'm trying to find an existence proof and possibly a constructive proof if I can get that far. – Candles – 2015-11-04T08:15:50.873
@Candles If you can prove that the worst case is repeated 9's (empirically correct up to quite a few repeated 9's), there's your constructive proof. – anatolyg – 2015-11-04T10:51:05.007
@SuperJedi224 multiples of mine that fit this answer will be at minimum 111111111, because any number x where x % 9 = 0, the numbers added up recursively will equal 9 – Stan Strum – 2017-09-22T22:04:11.127