SRM 552 div1 med FoxAndFlowerShopDivOne
問題
TopCoder Statistics - Problem Statement
H*W のグリッドが与えられる。各セルには 'P' か 'L' か '.' と書かれている。このグリッドから, 2 つの長方形を交差しないように選び, 以下の条件を満たすもとで 2 つの長方形内の 'L' の数 + 'P' の数 を最大化したい。最大値を求めよ。
条件: 2 つの長方形内の 'L' の数と 'P' の数の差の絶対値は maxDiff 以下である。
解法
O(n^6) で無理やり通したんですが, O(n^5) がありました。
下の問題と設定が酷似しています。
mayokoex.hatenablog.com
今回もこのアイデアと同様, 「交差してない -> x 方向か y 方向で交差していない」ということを利用します。ということで, 方針としては,
- 左側の長方形の x0, x1 を決める
- 右側の長方形の x2, x3, y0, y1 を決めて, 各長方形について l-p の値ごとに l+p の値を最大化する(mp[l-p] = max(l+p) とメモしておく)
- 左側の長方形の y0, y1 を決めて, 各長方形について mp の情報を使って l+p を最大化する(mp をなめるのに O(n^2) かかる)
となります。これだと O(n^6) になりますが,
- 左側と右側を分ける x 座標 vx を決める
- 左側, 右側について 長方形を O(n^4) で調べ, l-p の値ごとに l+p を最大化する(left, right という配列にメモ)
- left, right を使って条件を満たす範囲で l+p を最大化する
とやれば O(n^5) になります。なるべく対称性を保つようにやると計算量削減しやすそうですね。
今のだと x 方向に交差しない場合しか考えてませんが長方形を 90 度回転させて同じことをやれば y 方向に交差しない場合も同じように求められます。
const int MAXN = 33; const int B = MAXN*MAXN; int sum[2][MAXN][MAXN]; int mp[2*B]; int getSum(int type, int y0, int x0, int y1, int x1) { return sum[type][y1][x1] - sum[type][y1][x0] - sum[type][y0][x1] + sum[type][y0][x0]; } int calc(vector<string> flowers, int maxDiff) { memset(sum, 0, sizeof(sum)); int H = flowers.size(), W = flowers[0].size(); for (int i = 0; i < H; i++) for (int j = 0; j < W; j++) { for (int k = 0; k < 2; k++) sum[k][i+1][j+1] = sum[k][i+1][j] + sum[k][i][j+1] - sum[k][i][j]; if (flowers[i][j] == 'L') sum[0][i+1][j+1]++; if (flowers[i][j] == 'P') sum[1][i+1][j+1]++; } int ret = -1; for (int x0 = 0; x0 < W; x0++) for (int x1 = x0+1; x1 <= W; x1++) { memset(mp, -1, sizeof(mp)); for (int y0 = 0; y0 < H; y0++) for (int y1 = y0+1; y1 <= H; y1++) { for (int x2 = x1; x2 < W; x2++) for (int x3 = x2+1; x3 <= W; x3++) { int l = getSum(0, y0, x2, y1, x3); int p = getSum(1, y0, x2, y1, x3); mp[l-p+B] = max(l+p, mp[l-p+B]); } } for (int y0 = 0; y0 < H; y0++) for (int y1 = y0+1; y1 <= H; y1++) { int l = getSum(0, y0, x0, y1, x1); int p = getSum(1, y0, x0, y1, x1); for (int i = max(0, -maxDiff+p-l+B); i <= min(2*B-1, maxDiff+p-l+B); i++) { if (mp[i] != -1) ret = max(ret, mp[i]+l+p); } } } return ret; } class FoxAndFlowerShopDivOne { public: int theMaxFlowers(vector <string> flowers, int maxDiff) { int ret = -1; ret = max(ret, calc(flowers, maxDiff)); int H = flowers.size(), W = flowers[0].size(); vector<string> tmp(W); for (int i = 0; i < W; i++) { tmp[i].resize(H); for (int j = 0; j < H; j++) { tmp[i][j] = flowers[j][i]; } } ret = max(ret, calc(tmp, maxDiff)); return ret; } };