1280. Three Small Numbers Inside One Integer
Three values a, b and c, each from 0 to 1023, are to be carried in a
single integer. The layout is fixed:
bits 29..20 a
bits 19..10 b
bits 9..0 c
Answer q instructions. P a b c prints the packed integer; U v prints the
three fields of v, in the order a b c.
P 1 2 3 -> 1050627
U 1049603 -> 1 1 3
P 1023 1023 1023 -> 1073741823
## What most people try first
Three separate variables, or a small array. That is the right thing to do most of the time, and it is not what this is for. Packing earns its place when the triple has to be a single value: a key in a hash map, an entry in an array indexed by state, a return value from a function that may only return one thing, or a column in a table that stores one integer.
The instinct that causes bugs is reaching for decimal digits instead,
a * 1000000 + b * 1000 + c. That works here because the fields happen to be
under 1000, and it is strictly worse: it needs division to unpack, the field
boundaries are not powers of two so masks do not apply, and at
a = b = c = 1023 it produces 1024047575 while the bit version produces
1073741823. Only the second uses the integer's full capacity.
## The arithmetic, stated exactly
Each field is 10 bits wide, so its mask is (1 << 10) - 1 = 1023, and the
offsets are 0, 10 and 20.
pack: v = (a << 20) | (b << 10) | c
unpack: a = (v >> 20) & 1023
b = (v >> 10) & 1023
c = v & 1023
The shift moves a field to its position, and the mask removes everything above it. The highest field needs no mask when the value is known to fit, because there is nothing above it, but writing the mask anyway costs nothing and makes the three lines read identically.
## Why the OR is safe
The three shifted values occupy disjoint bit ranges, because each field is
exactly as wide as the gap to the next offset. So no bit is claimed twice and
the OR cannot lose information. That is the whole correctness condition for
packing: sum of widths <= width of the container, and offsets that leave no
overlap. Had the fields been 11 bits wide at offsets 0, 10 and 20 they would
collide, and b's top bit would silently corrupt a's bottom bit.
## Width
Three 10-bit fields occupy exactly 30 bits, so the packed value runs from 0 to
2^30 - 1 = 1073741823. That fits in a signed 32-bit integer, whose limit is
2147483647, with one bit of headroom.
JavaScript is safe here with plain Numbers, and this is worth checking rather
than assuming: (1023 << 20) | (1023 << 10) | 1023 evaluates to 1073741823
in JavaScript, which was run to confirm. It stays safe precisely because 30 is
below 31. #1281 next door uses 34 bits and JavaScript's << breaks there.
Constraints - `1 ≤ q ≤ 100000` - `0 ≤ a, b, c ≤ 1023` - `0 ≤ v ≤ 1073741823`
Input
The first line contains an integer q.
Each of the next q lines is either P a b c or U v.
Output
For each P print one integer on its own line: the packed value. For each U print three integers on one line separated by single spaces: the fields a, b and c in that order.
Hints
Four rungs, in order. The last two open once you have submitted an attempt. A wrong one counts.