# Decibinary Numbers

# Decibinary Numbers

tdprime + 4 comments I want to provide a hint for people who are still trying to wrap their head around the problem. One advanced book that is on topic is, "Combinatorial Algorithms", by Kreher and Stinson.

My breakthrough happened when I printed out a few tables. Given a function that converts decibinary to its decimal value, the 1 digit numbers have their obvious decimal values. I recommend printing tables of decibinary numbers in groups of 10, then you will start seeing a pattern.

In python, this might look like,

>>> [ db_value(x) for x in range(0,10) ] [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] >>> [ db_value(x) for x in range(10,20) ] [2, 3, 4, 5, 6, 7, 8, 9, 10, 11] >>> [ db_value(x) for x in range(20,30) ] [4, 5, 6, 7, 8, 9, 10, 11, 12, 13] >>> [ db_value(x) for x in range(90,100) ] [18, 19, 20, 21, 22, 23, 24, 25, 26, 27] >>> [ db_value(x) for x in range(100,110) ] [4, 5, 6, 7, 8, 9, 10, 11, 12, 13]

xl6v8 + 0 comments Your observation is brilliant!

superparkourio + 1 comment I'm still confused by this problem. How can we work backwards from this pattern to get all the decibinary values for a particular decimal as well as what decimal we need the decibinary values for?

labels + 0 comments My current 60% solution isn't based on this observation at all, I'm trying to understand it so I can make a 100% solution. I don't know how tdprime uses this at all, so I can only guess.

Consider this: When iterating through the numbers this way, what do you know about the numbers 0-4 once you have reached 100?

antonioaltamura7 + 0 comments just wow... but this implies you have precomputed a map, am I right?

anandbhanu33 + 0 comments range(0,9).. range(10,19).. ... range(90,99)..

posto84 + 0 comments Example tests:

2 1104 1963

result:

11111 (31 in decibinary) 10406 (38 written in decibinary)

craig53 + 0 comments C++ solution which is logically the same as the one posted previously but hopefully a little easier to understand.

const int dmax = 300000; const int digits = 10; const int powers = 20; vector<vector<long>> v(dmax, vector<long>(powers)); vector<long> c(dmax); // Complete the decibinaryNumbers function below. void preCompute() { // Compute the number of duplicates for each value, number of digits. for (int i = 0; i < dmax; i++) { v[i][0] = i < digits; for (int j = 1; j < powers; j++) { // Duplicates is sum of all shorter numbers duplicates for each digit. for (int k = 0; k < digits; k++) { int value = i - k * (1 << j); // Exit if using digit creates number larger than target value. if (value < 0) break; v[i][j] += v[value][j - 1]; } } } // Calculate the absolute offset for the first duplicate of each number. for (int i = 1; i < dmax; i++) { c[i] = v[i - 1][powers - 1] + c[i - 1]; } } long decibinaryNumbers(long x) { long result = 0; auto l = upper_bound(c.begin(), c.end(), x - 1) - 1; int value = l - c.begin(); long offset = (x - 1) - *l; // Find each digit. for (int i = powers - 1; i >= 1; i--) { int power = 1 << i; // Find the digit which takes us closest to offset. for (int digit = 0; digit < digits; digit++) { // Calculate value of remaining digits. int v1 = value - digit * power; // If index is less than duplicates for remainder we have our digit. if (offset < v[v1][i - 1]) { result += digit; value -= power * digit; break; } // Subtract number of duplicates for this digit from offset. offset -= v[v1][i - 1]; } result *= 10; } // Whatever is left must be the last digit. result += value; // cout << x << ":" << result << ":" << l - c.begin() << endl; return result; }

ryan249 + 0 comments I tried Java 8 but I am having some problems.

hungerfordj + 0 comments Can anyone help suggest a further optimization for the following solution? (I've implemented it in python; it passes 6/11 tests and times out the rest).

1) Figure out the number of decibinary numbers corresponding to each decimal number using the following dynamic programming algorithm suggested by xinwzh:

- where
`g[dec][dig]`

gives the number of decibinary numbers equal in value to decimal {dec} with at most {dig} digits, you can get`g[dec][dig]`

from:`g[dec][dig - 1] + g[dec - offset][dig - 1] + g[dec - 2 x offset][dig - 1] + g[dec - 3 x offset][dig - 1] + ... + g[0][dig - 1]`

, where`offset = 2^(dig - 1)`

. - Total number of decibinary numbers equal to a given decimal number is retrieved by:
`g[dec][length of g[dec] - 1]`

2) Add up the number of decibinary numbers corresponding to each decimal from

`0, 1, 2, 3, etc.`

until the total is greater than the query.- The decimal that put it over the list is the decimal corresponding to the queried decibinary.
- The queried decibinary will be the nth decibinary of that decimal, where n is the difference between the query and the
*previous*total (i.e. all the decibinaries up to but not including the decimal corresponding to the queried decibinary).

3) Find the queried decibinary by either a) finding the first decibinary and cycling up

`n`

times, or b) finding the last and cycling down`g[dec][len(gs[dec]) -1] - n`

times.- Find the next highest decibinary corresponding to the same decimal number by incrementing up the digits and looking for the first pair of digits where you can subtract two from the lower digit and add one to the higher digit. i.e., 200 -> 1000, 54 -> 62. However, you also need to go back down the digits and maximize in the other direction: 1900 -/-> 2700, 1900 -> 2188.
- Find the next lowest decibinary by the same thing, but reversed

Does anyone see where I might be able to optimize something further?? Is it possible to find the nth decibinary number equal to a given decimal number without cycling through the way I'm doing? (This is the bottleneck.)

- where

Sort 17 Discussions, By:

Please Login in order to post a comment