Wannafly挑战赛2 C.Butterfly(线段树优化枚举)
题目链接 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; }