CS302

September, 2011

Problem description: http://community.topcoder.com/stat?c=problem_statement&pm=11191&rd=14242

To solve this problem, you need to break it into the important pieces. As
always, it's good to check the constraints, since they sometimes help you figure
out if an approach is reasonable. In this case, since **roses** and **lilies**
have a maximum of 16 elements, you can think "enumeration." In particular, there
are 2^{16} potential combinations of packets that you can purchase, and
since that's a pretty small number (roughly 64,000), you can enumerate them.

For each combination of packets, you'll have *tr* roses and *tl* lilies.
The next question is which rectangular areas will correspond to *tr+tl* flowers.
The final question is whether a rectangular area will correspond to one which will
make a checkerboard pattern with *tr+tl* flowers.

Again, it helps to think about the constraints. Each element of **roses** and **lilies**
is a number between 0 and 10,000, so the maximum number of roses and lilies is 320,000.
Suppose we check all possible rectangles -- how would we do that? Let's represent the
number of rows in a rectangle with *r* and the number of columns with *c*.
First we can
notice that any rectangle where *r > c* is equivalent to a rectangle with *c*
rows and *r* columns, so we can restrict ourselves to rectangles where *r ≤ c*.
Let's enumerate them:

- The rectangle with
*r=1*has*c = (tl+tr)*. - The rectangle with
*r=2*has*c = (tl+tr)/2*and only exists if*(tl+tr)*is divisible by 2. - The rectangle with
*r=3*has*c = (tl+tr)/3*and only exists if*(tl+tr)*is divisible by 3. - Continue in this fashion until
*r*is so big that*r > c*. This will happen when*r*.^{2}> (tl+tr)

Finally, suppose we have a rectangle with *r* rows and *c* columns. Can you make a
checkerboard of roses and lilies from it? Break it into cases. If *c* is an even
number, then each row must have the same number of roses and lilies. That means that
*tr* must equal *tl*. The same is true if *r* is an even number. The
only tricky case is when both *r* and *c* are odd. Then, the rectangle with *r*
rows and *c-1* columns will have an equal number of rows and lillies. The last column
will either have one extra rose or one extra lily. Do some examples to convince yourself
of this. The code is pretty straightforward -- we'll write a procedure to test:

int is_valid(int r, int c, int tr, int tl) { if (c%2 == 0 || r%2 == 0) return (tr == tl); return (tl == tr+1 || tr == tl+1); } |

Next, let's perform the enumeration using bit arithmetic, and search for
valid *r* and *c*. Here's the rest of the code
(in **SRM-489-D2-500.cpp**):

int BuyingFlowers::buy(vector <int> roses, vector <int> lilies) { int i, e, tr, tl, r, c; int min; min = 1000000; // Sentinel for (e = 1; e < (1 << roses.size()); e++) { tr = 0; tl = 0; for (i = 0; i < roses.size(); i++) { if (e & (1 << i)) { tr += roses[i]; tl += lilies[i]; } } for (r = 1; r*r <= (tr+tl); r++) { if ((tr+tl)%r == 0) { c = (tr+tl)/r; if (is_valid(r, c, tr, tl)) if (c-r < min) min = c-r; } } } if (min == 1000000) min = -1; return min; } |

We compile and test, and it works on the test cases:

UNIX>Do we submit??? No, not yet. Let's add test case #4: 16 packets where every packet is 10,000. This will let us test whether our program is too slow. I've put that intog++ SRM-489-D2-500-Main.cppUNIX>a.out 01 UNIX>a.out 10 UNIX>a.out 2-1 UNIX>a.out 336 UNIX>

UNIX>Good -- it's fast enough, and is that answer correct? Well, 10,000 is a perfect square, so any case with two packets will have 40,000 seeds, which is a perfect square, and sincetime a.out 40 0.188u 0.001s 0:00.18 100.0% 0+0k 0+0io 0pf+0w UNIX>

Submit.

Could we make this faster? Of course. If

In a more difficult vein, we could prime-factor *tr+tl*, and then test all subsets
of the prime factorization. That would give us another reason to use bit arithmetic!
Fortunately, for the purposes of Topcoder, we don't have to; however, were we writing
production code that did something of this ilk, the prime factorization may be the
better way to go.