20240216 模拟赛 T2 题解

Description

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

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

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

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

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

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

Solution

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

考虑最小割,转化为代数形式,形如 \(\sum{a_i\overline{b_j}w_{i,j}}\),这样只要连一条 \(i\to j\) 流量为 \(w_{i,j}\) 的边,然后如果 \(i\) 和源点在一起,\(j\) 和汇点在一起即可造成贡献。

\(a_{i,j}\) 表示 \((i,j)\) 被行染成了黑色,\(b_{i,j}\) 表示 \((i,j)\) 被行染成了白色,\(c_{i,j}\) 表示 \((i,j)\) 被列染成了黑色,\(d_{i,j}\) 表示 \((i,j)\) 被列染成了白色。

先考虑操作 \(1\) 的贡献。对于 \((i,j)\) 染黑的贡献显然是 \(A\times a_{i,j}+B\times a_{i,j}\times \overline{a_{i,j+1}}+A\times c_{i,j}+B\times c_{i,j}\times \overline{c_{i+1,j}}\),染白同理。

然后是操作 \(2\) 的贡献。

先是黑点:如果操作 \(1\) 被染成了白色,那么显然不行,所以是 \(\infty\times(b_{i,j}+d_{i,j})\)。然后如果操作 \(1\) 没被染成黑色就要有 \(C\) 的贡献,所以是 \(C\times(\overline{a_{i,j}}\times\overline{c_{i,j}})\)

再是白点:如果操作 \(1\) 染了两次白色,显然不行,所以是 \(\infty\times(a_{i,j}\times c_{i,j})\)。然后如果操作 \(1\) 没被染成白色就要有 \(C\) 的贡献,所以是 \(C\times(a_{i,j}\times\overline{d_{i,j}}+c_{i,j}\times\overline{b_{i,j}})\)

把总的贡献写出来后发现 \(\overline{a_{i,j}}\times\overline{c_{i,j}}\) 是不合法的,所以把 \(b_{i,j}\) 变为 \(\overline{b_{i,j}}\)\(c_{i,j}\) 变为 \(\overline{c_{i,j}}\) 即可。

然后跑网络流即可。

时间复杂度:\(O(n^3 m^3)\)

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 @ 2024-02-16 21:37  下蛋爷  阅读(13)  评论(0)    收藏  举报