Repository navigation
Expand file tree
/
Copy pathDecibinaryNumbers.cs
More file actions
96 lines (82 loc) · 2.85 KB
/
Copy pathDecibinaryNumbers.cs
File metadata and controls
96 lines (82 loc) · 2.85 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
namespace HackerRank.Solutions.DynamicProgramming;
/// <summary>
/// Decibinary Numbers — decimal digits 0–9 with binary place values (digit i is worth
/// d · 2^i). List every decibinary number sorted by value, then by its own decimal value;
/// return the x-th. ways[p, v] counts representations of v using the lowest p positions.
/// Prefix sums over values find the value of the x-th number. Then digits are chosen from
/// the highest position down, skipping whole blocks of ways[p, rest] at each digit.
/// https://www.hackerrank.com/challenges/decibinary-numbers
/// </summary>
public static class DecibinaryNumbers
{
private const int Positions = 20;
public static long[] Solve(IReadOnlyList<long> queries)
{
long largest = queries.Max();
int maxValue = 16;
long[,] ways;
long[] cumulative;
// Grow the value range until it holds at least `largest` numbers.
while (true)
{
ways = BuildWays(maxValue);
cumulative = new long[maxValue + 1];
long running = 0;
for (int v = 0; v <= maxValue; v++)
{
running += ways[Positions, v];
cumulative[v] = running;
}
if (running >= largest)
{
break;
}
maxValue *= 2;
}
var results = new long[queries.Count];
for (int q = 0; q < queries.Count; q++)
{
long x = queries[q];
int value = Array.FindIndex(cumulative, c => c >= x);
long rank = x - (value > 0 ? cumulative[value - 1] : 0) - 1;
long number = 0;
int remaining = value;
for (int p = Positions - 1; p >= 0; p--)
{
for (int digit = 0; digit <= 9; digit++)
{
int rest = remaining - digit * (1 << p);
long count = rest >= 0 ? ways[p, rest] : 0;
if (rank < count)
{
number = number * 10 + digit;
remaining = rest;
break;
}
rank -= count;
}
}
results[q] = number;
}
return results;
}
private static long[,] BuildWays(int maxValue)
{
var ways = new long[Positions + 1, maxValue + 1];
ways[0, 0] = 1;
for (int p = 0; p < Positions; p++)
{
long place = 1L << p;
for (int v = 0; v <= maxValue; v++)
{
long total = 0;
for (int digit = 0; digit <= 9 && digit * place <= v; digit++)
{
total += ways[p, v - digit * place];
}
ways[p + 1, v] = total;
}
}
return ways;
}
}