20240216 模拟赛 T2 题解
Description
国师有两种魔法,第一种魔法可以选择一个
但是由于
同时,如果一个像素被重复绘制
除此之外,颜料的覆盖是允许的,并且该像素点的颜色由最后一次绘制的颜料决定。特别的,如果一个像素没有被任何颜料绘制,那么它会显示纸张的底色即白色。
作为国师的你希望通过最少的代价绘制出
Solution
容易发现同一行或者同一列两种相同颜色的矩形一定不相交,并且先涂
考虑最小割,转化为代数形式,形如
设
先考虑操作
然后是操作
先是黑点:如果操作
再是白点:如果操作
把总的贡献写出来后发现
然后跑网络流即可。
时间复杂度:
Code
#include <bits/stdc++.h> #define int int64_t const int kMaxN = 45, kMaxS = 6405, kMaxM = kMaxS * 10, kInf = 1e12; int n, m, A, B, C, s, t; int getid(int k, int x, int y) { return (k - 1) * n * m + (x - 1) * m + y; } namespace Dinic { struct Edge { int v, w, pre; } e[kMaxM]; int tot = 1; int tail[kMaxS], cur[kMaxS], dep[kMaxS]; void clear() { for (int i = 1; i <= t; ++i) { tail[i] = cur[i] = dep[i] = 0; } for (int i = 1; i <= tot; ++i) { e[i].v = e[i].w = e[i].pre = 0; } tot = 1; } void adde(int u, int v, int w) { e[++tot] = {v, w, tail[u]}, tail[u] = tot; } void add(int u, int v, int w) { adde(u, v, w), adde(v, u, 0); } bool bfs() { std::queue<int> q; for (int i = 1; i <= std::max(t, n); ++i) { dep[i] = 1e9, cur[i] = tail[i]; } q.emplace(s), dep[s] = 1; for (; !q.empty();) { int u = q.front(); q.pop(); for (int i = tail[u]; i; i = e[i].pre) { int v = e[i].v; if (!e[i].w || dep[v] != 1e9) continue; dep[v] = dep[u] + 1, q.emplace(v); } } return dep[t] != 1e9; } int dfs(int u, int lim) { if (u == t || !lim) return lim; int flow = 0; for (int &i = cur[u]; i; i = e[i].pre) { int v = e[i].v, w = e[i].w; if (w && dep[v] == dep[u] + 1) { int fl = dfs(v, std::min(lim, w)); if (!fl) dep[v] = 1e9; e[i].w -= fl, e[i ^ 1].w += fl; lim -= fl, flow += fl; if (!lim) break; } } return flow; } int64_t maxflow() { int64_t ans = 0; for (; bfs(); ans += dfs(s, 1e18)) {} return ans; } } // namespace Dinic void dickdreamer() { Dinic::clear(); std::cin >> n >> m >> A >> B >> C; s = getid(4, n, m) + 1, t = getid(4, n, m) + 2; for (int i = 1; i <= n; ++i) { std::string str; std::cin >> str; str = " " + str; for (int j = 1; j <= m; ++j) { for (int k = 1; k <= 4; ++k) { Dinic::add(s, getid(k, i, j), kInf + A * (k == 2 || k == 3)); Dinic::add(getid(k, i, j), t, kInf + A * (k == 1 || k == 4)); } if (j < m) { Dinic::add(getid(1, i, j), getid(1, i, j + 1), B); Dinic::add(getid(2, i, j + 1), getid(2, i, j), B); } else { Dinic::add(getid(1, i, j), t, B); Dinic::add(s, getid(2, i, j), B); } if (i < n) { Dinic::add(getid(3, i + 1, j), getid(3, i, j), B); Dinic::add(getid(4, i, j), getid(4, i + 1, j), B); } else { Dinic::add(s, getid(3, i, j), B); Dinic::add(getid(4, i, j), t, B); } if (str[j] == '1') { Dinic::add(getid(3, i, j), getid(1, i, j), C); Dinic::add(s, getid(2, i, j), kInf); Dinic::add(getid(4, i, j), t, kInf); } else { Dinic::add(getid(1, i, j), getid(4, i, j), C); Dinic::add(getid(2, i, j), getid(3, i, j), C); Dinic::add(getid(1, i, j), getid(3, i, j), C); } } } std::cout << Dinic::maxflow() - 4ll * n * m * kInf << '\n'; } int32_t main() { #ifdef ORZXKR freopen("magic.in", "r", stdin); freopen("magic.out", "w", stdout); #endif std::ios::sync_with_stdio(0), std::cin.tie(0), std::cout.tie(0); int T = 1; std::cin >> T; while (T--) dickdreamer(); // std::cerr << 1.0 * clock() / CLOCKS_PER_SEC << "s\n"; return 0; }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步