Solution -「AGC 031E」Snuke the Phantom Thief
阿新 • • 發佈:2022-03-16
\(\mathscr{Description}\)
Link.
在一個網格圖內有 \(n\) 個格子有正價值,給出四種限制:橫 / 縱座標不大於 / 不小於 \(a\) 的格子不能選超過 \(b\) 個。求能選出格子價值之和的最大值。
\(n\le80\),座標範圍 \(1\le X\le100\),限制數量 \(m\le320\)。
\(\mathscr{Solution}\)
你看出來是網路流,但應當留意,圖本身也許不是全部。
大概感知一下,感覺是一個源點-橫座標-價值點-縱座標-匯點的模型,但很難同時處理座標上的字首和限制與字尾和限制。怎麼辦?列舉最終選出的格子數 \(k\),它給我們帶來了額外條件——對字尾的限制可以化歸為對字首的限制。
具體地,以橫座標為例,先人為限制按橫座標升序選格子。對於 \(b<k\) 的某個限制,若限制字首不超過 \(b\) 個,相當於選出的第 \(b+1..k\) 個格子的橫座標都得 \(>a\);若限制字尾不超過 \(b\) 個,相當於選出的第 \(1..k-b\) 個格子的橫座標都得 \(<a\)。縱座標同理,規定縱座標升序選即可,二者只是考慮角度不同,並不矛盾。依此跑費用流,若滿流,用最大費用更新答案即可。
複雜度 \(\mathcal O(n\operatorname{Dinic}(n,n^2))\),當然邊數可以優化至 \(\mathcal O(n\log n)\)
\(\mathscr{Code}\)
/*+Rainybunny+*/ #include <bits/stdc++.h> #define rep(i, l, r) for (int i = l, rep##i = r; i <= rep##i; ++i) #define per(i, r, l) for (int i = r, per##i = l; i >= per##i; --i) typedef long long LL; typedef std::pair<int, LL> PIL; #define fi first #define se second template <typename Tp> inline void chkmin(Tp& u, const Tp& v) { v < u && (u = v, 0); } template <typename Tp> inline void chkmax(Tp& u, const Tp& v) { u < v && (u = v, 0); } template <typename Tp> inline Tp imin(const Tp& u, const Tp& v) { return u < v ? u : v; } template <typename Tp> inline Tp imax(const Tp& u, const Tp& v) { return u < v ? v : u; } const int MAXN = 80, MAXM = 320, MAXX = 100, IINF = 0x3f3f3f3f; const LL LINF = 1ll << 60; namespace FG { const int MAXND = MAXN * 2 + MAXX * 2 + 2; const int MAXEG = MAXN * MAXN * 2 + MAXN * 3; int S, T, ecnt = 1, head[MAXND + 5], curh[MAXND + 5]; LL dis[MAXND + 5]; struct Edge { int to, flw; LL cst; int nxt; } graph[MAXEG * 2 + 5]; inline void clear() { ecnt = 1; rep (i, S, T) head[i] = 0; } inline void link(const int s, const int t, const int f, const LL c) { // printf("%d %d %d,%lld\n", s, t, f, c); graph[++ecnt] = { t, f, c, head[s] }, head[s] = ecnt; graph[++ecnt] = { s, 0, -c, head[t] }, head[t] = ecnt; } inline bool spfa() { static std::queue<int> que; static bool inq[MAXND + 5]; rep (i, S, T) dis[i] = LINF; dis[S] = 0, que.push(S); while (!que.empty()) { int u = que.front(); que.pop(), inq[u] = false; for (int i = head[u], v; i; i = graph[i].nxt) { if (graph[i].flw && dis[v = graph[i].to] > dis[u] + graph[i].cst) { dis[v] = dis[u] + graph[i].cst; if (!inq[v]) que.push(v), inq[v] = true; } } } return dis[T] != LINF; } inline PIL augment(const int u, int iflw) { if (u == T) return { iflw, 0 }; static bool instk[MAXND + 5]; instk[u] = true; PIL ret(0, 0); for (int &i = curh[u], v; i; i = graph[i].nxt) { if (graph[i].flw && !instk[v = graph[i].to] && dis[v] == dis[u] + graph[i].cst) { PIL t(augment(v, std::min(iflw, graph[i].flw))); ret.fi += t.fi, ret.se += t.se + t.fi * graph[i].cst; graph[i].flw -= t.fi, graph[i ^ 1].flw += t.fi, iflw -= t.fi; if (!iflw) break; } } if (!ret.fi) dis[u] = LINF; return instk[u] = false, ret; } inline PIL dinic() { PIL ret(0, 0); while (spfa()) { rep (i, S, T) curh[i] = head[i]; PIL t(augment(S, IINF)); ret.fi += t.fi, ret.se += t.se; } return ret; } } // namespace FG. int n, m, jx[MAXN + 5], jy[MAXN + 5]; int lefx[MAXN + 5], rigx[MAXN + 5], lefy[MAXN + 5], rigy[MAXN + 5]; LL jv[MAXN + 5]; struct Restrict { int op, a, b; } lim[MAXM + 5]; int main() { scanf("%d", &n); rep (i, 1, n) scanf("%d %d %lld", &jx[i], &jy[i], &jv[i]); scanf("%d", &m); rep (i, 1, m) { char op[5]; scanf("%s %d %d", op, &lim[i].a, &lim[i].b), lim[i].op = op[0]; } LL ans = 0; rep (x, 1, n) { // x = 4; // debug. FG::clear(); FG::S = 0, FG::T = 2 * x + 2 * n + 1; rep (i, 1, x) { FG::link(FG::S, i, 1, 0); FG::link(i + x, FG::T, 1, 0); } rep (i, 1, n) FG::link(i + 2 * x, i + n + 2 * x, 1, -jv[i]); rep (i, 1, x) lefx[i] = lefy[i] = 1, rigx[i] = rigy[i] = MAXX; rep (i, 1, m) if (lim[i].b < x) { if (lim[i].op == 'L') chkmax(lefx[lim[i].b + 1], lim[i].a + 1); if (lim[i].op == 'R') chkmin(rigx[x - lim[i].b], lim[i].a - 1); if (lim[i].op == 'U') chkmin(rigy[x - lim[i].b], lim[i].a - 1); if (lim[i].op == 'D') chkmax(lefy[lim[i].b + 1], lim[i].a + 1); } rep (i, 2, x) { chkmax(lefx[i], lefx[i - 1]), chkmax(lefy[i], lefy[i - 1]); } per (i, x - 1, 1) { chkmin(rigx[i], rigx[i + 1]), chkmin(rigy[i], rigy[i + 1]); } rep (i, 1, x) { rep (j, 1, n) { if (lefx[i] <= jx[j] && jx[j] <= rigx[i]) { FG::link(i, j + 2 * x, 1, 0); } if (lefy[i] <= jy[j] && jy[j] <= rigy[i]) { FG::link(j + n + 2 * x, i + x, 1, 0); } } } PIL res(FG::dinic()); if (res.fi == x) chkmax(ans, -res.se); // break; // debug } printf("%lld\n", ans); return 0; }