欢迎来到下蛋爷之家|

下蛋爷

园龄:4年2个月粉丝:8关注:23

20240216 模拟赛 T2 题解

Description

H 国的国王想要画一幅画,该幅画由黑白两种颜色组成,长 n 个像素,宽 m 个像素。作为国师的你需要使用魔法将它绘制到一张白纸上。

国师有两种魔法,第一种魔法可以选择一个 1×x 或者 x×1 的矩形,将其绘制成黑色或者白色,消耗 Ax+B 的代价。第二种魔法可以选择一个 1×1 的像素,将其绘制成黑色或者白色,消耗 C 的代价。

但是由于 H 国的颜料产业还处于发展阶段,颜料很容易发生混杂。具体来说,如果一个像素先被白色颜料绘制,再被黑色颜料绘制,那么它会变成一种奇怪的颜色。但是反过来先用黑色再用白色不会发生这种情况

同时,如果一个像素被重复绘制 3 次及以上,那么这个像素的颜料会扩散,也会变成一种奇怪的颜色。

除此之外,颜料的覆盖是允许的,并且该像素点的颜色由最后一次绘制的颜料决定。特别的,如果一个像素没有被任何颜料绘制,那么它会显示纸张的底色即白色。

作为国师的你希望通过最少的代价绘制出 H 国国王想要的画。你想要知道代价最小是多少。

Solution

容易发现同一行或者同一列两种相同颜色的矩形一定不相交,并且先涂 1 操作黑色 1 操作白色 2 操作一定最优。

考虑最小割,转化为代数形式,形如 aibjwi,j,这样只要连一条 ij 流量为 wi,j 的边,然后如果 i 和源点在一起,j 和汇点在一起即可造成贡献。

ai,j 表示 (i,j) 被行染成了黑色,bi,j 表示 (i,j) 被行染成了白色,ci,j 表示 (i,j) 被列染成了黑色,di,j 表示 (i,j) 被列染成了白色。

先考虑操作 1 的贡献。对于 (i,j) 染黑的贡献显然是 A×ai,j+B×ai,j×ai,j+1+A×ci,j+B×ci,j×ci+1,j,染白同理。

然后是操作 2 的贡献。

先是黑点:如果操作 1 被染成了白色,那么显然不行,所以是 ×(bi,j+di,j)。然后如果操作 1 没被染成黑色就要有 C 的贡献,所以是 C×(ai,j×ci,j)

再是白点:如果操作 1 染了两次白色,显然不行,所以是 ×(ai,j×ci,j)。然后如果操作 1 没被染成白色就要有 C 的贡献,所以是 C×(ai,j×di,j+ci,j×bi,j)

把总的贡献写出来后发现 ai,j×ci,j 是不合法的,所以把 bi,j 变为 bi,jci,j 变为 ci,j 即可。

然后跑网络流即可。

时间复杂度:O(n3m3)

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;
}
posted @   下蛋爷  阅读(9)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
收起