def get_intersection(rect1, rect2):
y1, x1, y2, x2 = rect1
y3, x3, y4, x4 = rect2
return (
max(0, 1 + min(x4, x2) - max(x1, x3)) *
max(0, 1 + min(y4, y2) - max(y1, y3))
)
def solve_stupid(N, M, R, C, parks):
min_trees = None
best_pos = None
for r in xrange(1, N - R + 2):
for c in xrange(1, M - C + 2):
trees = 0
for park in parks:
trees += get_intersection((r, c, r + R - 1, c + C - 1), park)
if min_trees is None or min_trees > trees:
min_trees = trees
best_pos = (r, c)
return min_trees, best_pos
def get_interesting(a1, a2, l, total):
# growing starts at pos such that pos + l == a1
grow_start = max(1, a1 - l)
# growing stops at pos = a1
grow_stop = a1
# falling starts at pos such that pos + l - 1 = a2
fall_start = max(1, a2 - l + 1)
# falling stops at pos right after a2: pos = a2 + 1
fall_stop = a2 + 1
# squeeze coordinates that don't fit
grow_start = min(grow_start, total)
grow_stop = min(grow_stop, total)
fall_start = min(fall_start, total)
fall_stop = min(fall_stop, total)
return grow_start, grow_stop, fall_start, fall_stop
def solve_smart(N, M, R, C, parks):
interesting_rows = set([1])
interesting_cols = set([1])
for park in parks:
r1, c1, r2, c2 = park
interesting_rows.update(get_interesting(r1, r2, R, N - R + 1))
interesting_cols.update(get_interesting(c1, c2, C, M - C + 1))
rows = sorted(interesting_rows)
cols = sorted(interesting_cols)
col_to_index = {col: i for i, col in enumerate(cols)}
min_trees = None
best_pos = None
for r in rows:
deriv_changes = [0] * len(cols)
for park in parks:
r1, c1, r2, c2 = park
gstart, gstop, fstart, fstop = get_interesting(c1, c2, C, M - C + 1)
park_height = get_intersection(
(r, c1, r + R - 1, c1),
park
)
deriv_changes[col_to_index[gstart]] += park_height
deriv_changes[col_to_index[gstop]] -= park_height
deriv_changes[col_to_index[fstart]] -= park_height
deriv_changes[col_to_index[fstop]] += park_height
# now we know how derivative changes and we need
# initial value to start with
trees = 0
first_col = cols[0]
for park in parks:
trees += get_intersection(
park,
(r, first_col, r + R - 1, first_col + C - 1)
)
if min_trees is None or min_trees > trees:
min_trees = trees
best_pos = (r, first_col)
derivative = 0
for i, col in enumerate(cols[:-1]):
derivative += deriv_changes[i]
next_col = cols[i + 1]
trees += (next_col - col) * derivative
if trees < min_trees:
min_trees = trees
best_pos = (r, next_col)
return min_trees, best_pos
solve = solve_smart
print solve_smart(5, 3, 2, 2, [
(2, 2, 2, 2),
(4, 2, 4, 2),
])
print solve_smart(5, 5, 3, 2, [
(1, 1, 1, 5),
(2, 1, 5, 1),
(5, 2, 5, 5),
(2, 5, 4, 5),
(3, 3, 3, 4),
])
N = 100
M = 100
K = 50
import random
for R in xrange(1, N + 1):
C = R
parks = []
for i in xrange(K):
while True:
r1 = random.randrange(1, N + 1)
c1 = random.randrange(1, M + 1)
r2 = random.randrange(r1, N + 1)
c2 = random.randrange(c1, M + 1)
new_park = (r1, c1, r2, c2)
for park in parks:
if get_intersection(new_park, park):
break
else:
parks.append(new_park)
break
smart = solve_smart(N, M, R, C, parks)
stupid = solve_stupid(N, M, R, C, parks)
if smart != stupid:
print "FAIL"
print smart
print stupid
print parks
print N, M, R, C
raise SystemExit
CmRlZiBnZXRfaW50ZXJzZWN0aW9uKHJlY3QxLCByZWN0Mik6CiAgICB5MSwgeDEsIHkyLCB4MiA9IHJlY3QxCiAgICB5MywgeDMsIHk0LCB4NCA9IHJlY3QyCiAgICByZXR1cm4gKAogICAgICAgIG1heCgwLCAxICsgbWluKHg0LCB4MikgLSBtYXgoeDEsIHgzKSkgKgogICAgICAgIG1heCgwLCAxICsgbWluKHk0LCB5MikgLSBtYXgoeTEsIHkzKSkKICAgICkKCmRlZiBzb2x2ZV9zdHVwaWQoTiwgTSwgUiwgQywgcGFya3MpOgogICAgbWluX3RyZWVzID0gTm9uZQogICAgYmVzdF9wb3MgPSBOb25lCiAgICBmb3IgciBpbiB4cmFuZ2UoMSwgTiAtIFIgKyAyKToKICAgICAgICBmb3IgYyBpbiB4cmFuZ2UoMSwgTSAtIEMgKyAyKToKICAgICAgICAgICAgdHJlZXMgPSAwCiAgICAgICAgICAgIGZvciBwYXJrIGluIHBhcmtzOgogICAgICAgICAgICAgICAgdHJlZXMgKz0gZ2V0X2ludGVyc2VjdGlvbigociwgYywgciArIFIgLSAxLCBjICsgQyAtIDEpLCBwYXJrKQogICAgICAgICAgICBpZiBtaW5fdHJlZXMgaXMgTm9uZSBvciBtaW5fdHJlZXMgPiB0cmVlczoKICAgICAgICAgICAgICAgIG1pbl90cmVlcyA9IHRyZWVzCiAgICAgICAgICAgICAgICBiZXN0X3BvcyA9IChyLCBjKQogICAgcmV0dXJuIG1pbl90cmVlcywgYmVzdF9wb3MKCgoKZGVmIGdldF9pbnRlcmVzdGluZyhhMSwgYTIsIGwsIHRvdGFsKToKICAgICMgZ3Jvd2luZyBzdGFydHMgYXQgcG9zIHN1Y2ggdGhhdCBwb3MgKyBsID09IGExCiAgICBncm93X3N0YXJ0ID0gbWF4KDEsIGExIC0gbCkKICAgICMgZ3Jvd2luZyBzdG9wcyBhdCBwb3MgPSBhMQogICAgZ3Jvd19zdG9wID0gYTEKCiAgICAjIGZhbGxpbmcgc3RhcnRzIGF0IHBvcyBzdWNoIHRoYXQgcG9zICsgbCAtIDEgPSBhMgogICAgZmFsbF9zdGFydCA9IG1heCgxLCBhMiAtIGwgKyAxKQogICAgIyBmYWxsaW5nIHN0b3BzIGF0IHBvcyByaWdodCBhZnRlciBhMjogcG9zID0gYTIgKyAxCiAgICBmYWxsX3N0b3AgPSBhMiArIDEKCiAgICAjIHNxdWVlemUgY29vcmRpbmF0ZXMgdGhhdCBkb24ndCBmaXQKICAgIGdyb3dfc3RhcnQgPSBtaW4oZ3Jvd19zdGFydCwgdG90YWwpCiAgICBncm93X3N0b3AgPSBtaW4oZ3Jvd19zdG9wLCB0b3RhbCkKICAgIGZhbGxfc3RhcnQgPSBtaW4oZmFsbF9zdGFydCwgdG90YWwpCiAgICBmYWxsX3N0b3AgPSBtaW4oZmFsbF9zdG9wLCB0b3RhbCkKCiAgICByZXR1cm4gZ3Jvd19zdGFydCwgZ3Jvd19zdG9wLCBmYWxsX3N0YXJ0LCBmYWxsX3N0b3AKCmRlZiBzb2x2ZV9zbWFydChOLCBNLCBSLCBDLCBwYXJrcyk6CiAgICBpbnRlcmVzdGluZ19yb3dzID0gc2V0KFsxXSkKICAgIGludGVyZXN0aW5nX2NvbHMgPSBzZXQoWzFdKQoKICAgIGZvciBwYXJrIGluIHBhcmtzOgogICAgICAgIHIxLCBjMSwgcjIsIGMyID0gcGFyawogICAgICAgIGludGVyZXN0aW5nX3Jvd3MudXBkYXRlKGdldF9pbnRlcmVzdGluZyhyMSwgcjIsIFIsIE4gLSBSICsgMSkpCiAgICAgICAgaW50ZXJlc3RpbmdfY29scy51cGRhdGUoZ2V0X2ludGVyZXN0aW5nKGMxLCBjMiwgQywgTSAtIEMgKyAxKSkKCiAgICByb3dzID0gc29ydGVkKGludGVyZXN0aW5nX3Jvd3MpCiAgICBjb2xzID0gc29ydGVkKGludGVyZXN0aW5nX2NvbHMpCgogICAgY29sX3RvX2luZGV4ID0ge2NvbDogaSBmb3IgaSwgY29sIGluIGVudW1lcmF0ZShjb2xzKX0KCiAgICBtaW5fdHJlZXMgPSBOb25lCiAgICBiZXN0X3BvcyA9IE5vbmUKICAgIGZvciByIGluIHJvd3M6CiAgICAgICAgZGVyaXZfY2hhbmdlcyA9IFswXSAqIGxlbihjb2xzKQogICAgICAgIGZvciBwYXJrIGluIHBhcmtzOgogICAgICAgICAgICByMSwgYzEsIHIyLCBjMiA9IHBhcmsKICAgICAgICAgICAgZ3N0YXJ0LCBnc3RvcCwgZnN0YXJ0LCBmc3RvcCA9IGdldF9pbnRlcmVzdGluZyhjMSwgYzIsIEMsIE0gLSBDICsgMSkKICAgICAgICAgICAgcGFya19oZWlnaHQgPSBnZXRfaW50ZXJzZWN0aW9uKAogICAgICAgICAgICAgICAgKHIsIGMxLCByICsgUiAtIDEsIGMxKSwKICAgICAgICAgICAgICAgIHBhcmsKICAgICAgICAgICAgKQogICAgICAgICAgICBkZXJpdl9jaGFuZ2VzW2NvbF90b19pbmRleFtnc3RhcnRdXSArPSBwYXJrX2hlaWdodAogICAgICAgICAgICBkZXJpdl9jaGFuZ2VzW2NvbF90b19pbmRleFtnc3RvcF1dIC09IHBhcmtfaGVpZ2h0CiAgICAgICAgICAgIGRlcml2X2NoYW5nZXNbY29sX3RvX2luZGV4W2ZzdGFydF1dIC09IHBhcmtfaGVpZ2h0CiAgICAgICAgICAgIGRlcml2X2NoYW5nZXNbY29sX3RvX2luZGV4W2ZzdG9wXV0gKz0gcGFya19oZWlnaHQKCiAgICAgICAgIyBub3cgd2Uga25vdyBob3cgZGVyaXZhdGl2ZSBjaGFuZ2VzIGFuZCB3ZSBuZWVkCiAgICAgICAgIyBpbml0aWFsIHZhbHVlIHRvIHN0YXJ0IHdpdGgKICAgICAgICB0cmVlcyA9IDAKICAgICAgICBmaXJzdF9jb2wgPSBjb2xzWzBdCiAgICAgICAgZm9yIHBhcmsgaW4gcGFya3M6CiAgICAgICAgICAgIHRyZWVzICs9IGdldF9pbnRlcnNlY3Rpb24oCiAgICAgICAgICAgICAgICBwYXJrLAogICAgICAgICAgICAgICAgKHIsIGZpcnN0X2NvbCwgciArIFIgLSAxLCBmaXJzdF9jb2wgKyBDIC0gMSkKICAgICAgICAgICAgKQoKICAgICAgICBpZiBtaW5fdHJlZXMgaXMgTm9uZSBvciBtaW5fdHJlZXMgPiB0cmVlczoKICAgICAgICAgICAgbWluX3RyZWVzID0gdHJlZXMKICAgICAgICAgICAgYmVzdF9wb3MgPSAociwgZmlyc3RfY29sKQoKICAgICAgICBkZXJpdmF0aXZlID0gMAogICAgICAgIGZvciBpLCBjb2wgaW4gZW51bWVyYXRlKGNvbHNbOi0xXSk6CiAgICAgICAgICAgIGRlcml2YXRpdmUgKz0gZGVyaXZfY2hhbmdlc1tpXQogICAgICAgICAgICBuZXh0X2NvbCA9IGNvbHNbaSArIDFdCiAgICAgICAgICAgIHRyZWVzICs9IChuZXh0X2NvbCAtIGNvbCkgKiBkZXJpdmF0aXZlCiAgICAgICAgICAgIGlmIHRyZWVzIDwgbWluX3RyZWVzOgogICAgICAgICAgICAgICAgbWluX3RyZWVzID0gdHJlZXMKICAgICAgICAgICAgICAgIGJlc3RfcG9zID0gKHIsIG5leHRfY29sKQoKICAgIHJldHVybiBtaW5fdHJlZXMsICBiZXN0X3BvcwoKCnNvbHZlID0gc29sdmVfc21hcnQKCnByaW50IHNvbHZlX3NtYXJ0KDUsIDMsIDIsIDIsIFsKICAgICgyLCAyLCAyLCAyKSwKICAgICg0LCAyLCA0LCAyKSwKXSkKCnByaW50IHNvbHZlX3NtYXJ0KDUsIDUsIDMsIDIsIFsKICAgICgxLCAxLCAxLCA1KSwKICAgICgyLCAxLCA1LCAxKSwKICAgICg1LCAyLCA1LCA1KSwKICAgICgyLCA1LCA0LCA1KSwKICAgICgzLCAzLCAzLCA0KSwKXSkKCgpOID0gMTAwCk0gPSAxMDAKSyA9IDUwCgppbXBvcnQgcmFuZG9tCgpmb3IgUiBpbiB4cmFuZ2UoMSwgTiArIDEpOgogICAgQyA9IFIKICAgIHBhcmtzID0gW10KICAgIGZvciBpIGluIHhyYW5nZShLKToKICAgICAgICB3aGlsZSBUcnVlOgogICAgICAgICAgICByMSA9IHJhbmRvbS5yYW5kcmFuZ2UoMSwgTiArIDEpCiAgICAgICAgICAgIGMxID0gcmFuZG9tLnJhbmRyYW5nZSgxLCBNICsgMSkKICAgICAgICAgICAgcjIgPSByYW5kb20ucmFuZHJhbmdlKHIxLCBOICsgMSkKICAgICAgICAgICAgYzIgPSByYW5kb20ucmFuZHJhbmdlKGMxLCBNICsgMSkKICAgICAgICAgICAgbmV3X3BhcmsgPSAocjEsIGMxLCByMiwgYzIpCiAgICAgICAgICAgIGZvciBwYXJrIGluIHBhcmtzOgogICAgICAgICAgICAgICAgaWYgZ2V0X2ludGVyc2VjdGlvbihuZXdfcGFyaywgcGFyayk6CiAgICAgICAgICAgICAgICAgICAgYnJlYWsKICAgICAgICAgICAgZWxzZToKICAgICAgICAgICAgICAgIHBhcmtzLmFwcGVuZChuZXdfcGFyaykKICAgICAgICAgICAgICAgIGJyZWFrCgogICAgc21hcnQgPSBzb2x2ZV9zbWFydChOLCBNLCBSLCBDLCBwYXJrcykKICAgIHN0dXBpZCA9IHNvbHZlX3N0dXBpZChOLCBNLCBSLCBDLCBwYXJrcykKICAgIGlmIHNtYXJ0ICE9IHN0dXBpZDoKICAgICAgICBwcmludCAiRkFJTCIKICAgICAgICBwcmludCBzbWFydAogICAgICAgIHByaW50IHN0dXBpZAogICAgICAgIHByaW50IHBhcmtzCiAgICAgICAgcHJpbnQgTiwgTSwgUiwgQwogICAgICAgIHJhaXNlIFN5c3RlbUV4aXQ=