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 216 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:
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> g++ SRM-489-D2-500-Main.cpp UNIX> a.out 0 1 UNIX> a.out 1 0 UNIX> a.out 2 -1 UNIX> a.out 3 36 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 into SRM-489-D2-500-Main.cpp:
UNIX> time a.out 4 0 0.188u 0.001s 0:00.18 100.0% 0+0k 0+0io 0pf+0w 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 since tl == tr, our difference is indeed 0.
Submit.
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.