Editorial for Google Code Jam '22 Round 2 Problem B - Pixelated Circle


Remember to use this editorial only when stuck, and not to copy-paste code from it. Please be respectful to the problem author and editorialist.
Submitting an official solution before solving the problem yourself is a bannable offence.

Let C and Cw be the set of pixels colored by draw_circle_filled(R) and draw_circle_filled_wrong(R), the number of pixels that have different colors in these pictures would be the cardinality (size) of the symmetric difference of C and Cw, that is:

|CΔCw|=|(CCw)(CwC)|

Test Set 1

For test set 1, R is small enough to build the sets of colored pixels from draw_circle_filled(R) and draw_circle_filled_wrong(R) with hash set of tuples. By implementing the pseudocode in the problem statement, the time complexity would be O(R2) to get all colored pixels and O(R2) to compute the symmetric difference of the two sets.

Test Set 2

The key observation for optimizing the solution is that for any R, every pixel colored by draw_circle_filled_wrong(R) is also colored by draw_circle_filled(R), that is CwC. Therefore, we can simplify the size of symmetric difference to:

|CΔCw|=|(CCw)(CwC)|=|(CCw)|=|C||CCw|=|C||Cw|

which means we can count the number of pixels colored by draw_circle_filled(R) and draw_circle_filled_wrong(R) separately, and the answer would be the difference between these two numbers. The proof of this observation is given at the end of this analysis.

Count pixels colored by draw_circle_filled(R)

To get the number of pixels colored by draw_circle_filled(R), we need to iterate through all possible values of x and find ymin and ymax for each x which satisfy round(x2+y2)R for all yminyymax. A solution for them is ymax=floor(R+0.52x2) and ymin=ymax. Therefore, we can get the number of colored pixels with a for-loop for the following equation:

|C|=x=RRfloor((R+0.5)2x2)×2+1

Time complexity: O(R)

Count pixels colored by draw_circle_filled_wrong(R)

draw_circle_filled_wrong(R) is composed of draw_circle_perimeter(r) calls with r from 0 to R. Notice that pixels colored by draw_circle_perimeter(r1) and draw_circle_perimeter(r2) never overlap if r1r2. Based on this observation, we can count the number of pixels colored by each draw_circle_perimeter(r) separately and sum them up to get the total number of colored pixels. The proof of this observation is given at the end of this analysis.

Looking into function draw_circle_perimeter(r), we can break the colored pixels into 4 quadrants and count them separately. Since the colored pattern is symmetric to both x-axis and y-axis, we just need to count the pixels in Quadrant 1 (Q1), and the total count excluding the origin pixel would be that number times 4, and plus 1 to include the origin pixel.

For r1, the colored pixels in Q1 are symmetric to the line x=y, and there are exactly xt colored pixels between y-axis and (xt,yt), the closest point to line x=y (above or on the line, xtyt). Since x=y is at 45 to the x-axis, the integer xt would be either ceil(r/cos(45)) or floor(r/cos(45)). We can compute the corresponding yt=round(r2xt2) and choose the closer one above or on the line x=y. Afterwards, the number of colored pixels in Q1 including x-axis would be 2×xt+1, and minus 1 if (xt,yt) lies on the line x=y since it is not mirrored in this case.

Time complexity: O(1) for counting pixels colored by draw_circle_perimeter(r), and O(R) for all colored pixels.

Proof: CwC

For every positive R, r and x such that 0rR and rxr, we want to prove that the following inequality always satisfies:

round(x2+round(r2x2)2)rx2+round(r2x2)20.5rx2+round(r2x2)2r+0.5x2+round(r2x2)2r2+r+0.25x2+(r2x2+0.5)2r2+r+0.25r2+r2x2+0.25r2+r+0.25

which always holds since r2x2r2=r when |x|r and r0.

Secondly, y=round(r2x2)round(r2)R. Therefore RyR always holds.

The proof above shows that pixels colored by draw_circle_filled_wrong(r) with 0rR also satisfy the coloring condition in draw_circle_filled(R), which implies CwC.

Proof: draw_circle_perimeter(r1) and draw_circle_perimeter(r2) never overlap

For the first coloring statement in draw_circle_perimeter(r), we want to prove that given a fixed x, the inequality y1=round(r12x2)y2=round(r22x2) for any pair of integers r1 and r2 such that r1>r20 and |x|r2 is always true:

=|r12x2r22x2|=r12x2r22x2r1>r2r12x2(r11)2x2r1 and r2 are integers(r12x2)((r11)2x2)for any |x|r11=r1x(r11)+x=1

Based on the proof above, we can further get:

round(r12x2)round(r22x2)round(r12x2)round((r11)2x2)round(r12x2)round(r12x21)1

Therefore y1y2 always holds for all r1>r20 given a fixed x such that |x|r2. For the cases that r2<|x|r1, the pixels will never satisfy the coloring condition in draw_circle_perimeter(r2).

We can further extend the proof above for the 2nd, 3rd, and 4th coloring statement in draw_circle_perimeter(r) and prove that pixels colored by draw_circle_perimeter(r1) and draw_circle_perimeter(r2) never overlap.


Comments

There are no comments at the moment.