Wannafly挑戰賽2 C.Butterfly(線段樹優化枚舉)
阿新 • • 發佈:2017-12-02
bit push har char s href max pan 線段樹 ans
題目鏈接 C.Butterfly
令$fd[i][j]$為以$s[i][j]$為起點開始往下走最大連續的‘X’個數
令$fl[i][j]$為以$s[i][j]$為起點開始往左下走最大連續的‘X’個數
令$fr[i][j]$為以$s[i][j]$為起點開始往左下走最大連續的‘X’個數
令$a[i][j] = min(fd[i][j], fl[i][j])$, $b[i][j] = min(fd[i][j], fr[i][j])$
對於每一個$(i, j)$, 我們要找到$(i, k)$
使得$k$最大,並且$k >= j$, $k - j + 1 <= min(a[i][j], b[i][k])$
$k - j + 1$必須為奇數
把所有條件整理出來就是
$k - j + 1 <= a[i][j]$
$k - j + 1 <= b[i][k]$
移項得到
$k <= a[i][j] + j - 1$
$k - b[i][k] + 1 <= j$
所以我們可以對$k - b[i][k] + 1$排序,當$j$從$1$掃到$m$的時候每一次確保所有滿足$k - b[i][k] + 1$的$k$都已經被添加到線段樹中
那麽我們在$[j, a[i][j] + j - 1]$這段區間裏面查找最大值(也就是符合條件的最大的$k$)更新答案即可。
註意分奇偶討論
#include <bits/stdc++.h> using namespace std; #define rep(i, a, b) for (int i(a); i <= (b); ++i) #define dec(i, a, b) for (int i(a); i >= (b); --i) #define fi first #define se second #define MP make_pair #define lson i << 1, L, mid #define rson i << 1 | 1, mid + 1, R typedef pair <int, int> PII; const int N = 2010; char s[N][N]; int fd[N][N], fl[N][N], fr[N][N], a[N][N], b[N][N]; int n, m, now; int t[N << 4]; int cnt, mx, ans = 0; PII c[N]; inline void pushup(int i){ t[i] = max(t[i << 1], t[i << 1 | 1]); } void update(int i, int L, int R, int x, int val){ if (L == R && L == x){ t[i] = max(t[i], val); return; } int mid = (L + R) >> 1; if (x <= mid) update(lson, x, val); else update(rson, x, val); pushup(i); } int query(int i, int L, int R, int l, int r){ if (l <= L && R <= r) return t[i]; int mid = (L + R) >> 1; if (r <= mid) return query(lson, l, r); else if (l > mid) return query(rson, l, r); else return max(query(lson, l, r), query(rson, l, r)); } int main(){ scanf("%d%d", &n, &m); rep(i, 1, n) scanf("%s", s[i] + 1); dec(i, n, 1) rep(j, 1, m){ fd[i][j] = s[i][j] == ‘X‘ ? fd[i + 1][j] + 1 : 0; fl[i][j] = s[i][j] == ‘X‘ ? fl[i + 1][j - 1] + 1 : 0; fr[i][j] = s[i][j] == ‘X‘ ? fr[i + 1][j + 1] + 1 : 0; } rep(i, 1, n) rep(j, 1, m) a[i][j] = min(fd[i][j], fr[i][j]), b[i][j] = min(fd[i][j], fl[i][j]); mx = m << 1; ans = 0; rep(i, 1, n){ cnt = 0; for (int j = 1; j <= m; j += 2) if (b[i][j]) c[++cnt] = MP(j - b[i][j] + 1, j); sort(c + 1, c + cnt + 1); memset(t, 0, sizeof t); now = 0; for (int j = 1; j <= m; j += 2){ if (!a[i][j]) continue; while (now < cnt){ if (c[now + 1].fi <= j){ ++now; update(1, 1, mx, c[now].se, c[now].se); if (now >= cnt) break; } else break; } int et = query(1, 1, mx, j, a[i][j] + j - 1); ans = max(ans, et - j + 1); } cnt = 0; for (int j = 2; j <= m; j += 2) if (b[i][j]) c[++cnt] = MP(j - b[i][j] + 1, j); sort(c + 1, c + cnt + 1); memset(t, 0, sizeof t); now = 0; for (int j = 2; j <= m; j += 2){ if (!a[i][j]) continue; while (now < cnt){ if (c[now + 1].fi <= j){ ++now; update(1, 1, mx, c[now].se, c[now].se); if (now >= cnt) break; } else break; } int et = query(1, 1, mx, j, a[i][j] + j - 1); ans = max(ans, et - j + 1); } } printf("%d\n", ans); return 0; }
Wannafly挑戰賽2 C.Butterfly(線段樹優化枚舉)