CF1567F One-Four Overload

CF1567F One-Four Overload

我居然把这道 \(2700\) 的题切了!!!

\(-OHHHHHHHHHHHHHHHH!!!\)

没有标记的格子只能选 \(1\) 或者 \(4\) , 标记的格子必须是 \(5\) 的倍数.

比较显然的是, 标记的格子周围必须有且只能有偶数个 (包括 \(0\) ) 未标记的格子, 否则无解.

接下来我们考虑构造一组解.

比较显然的是, 如果一个标记的格子周围只有两个未标记的格子, 那么一定是一个 \(1\) 一个 \(4\) , 不管是 \(L\) 形还是 \(I\) 形.

如果有 \(4\) 个呢? 那么我们就把同一行的和同一列的填上相同的数. 为什么?

因为一对 \(I\) 形的未标记格子只可能对应一个标记的格子, 而一对 \(L\) 形的可能对应两个标记的格子, 所以我们只需要保证这 \(4\) 个未标记格子分别组成的两组 \(L\) 形合法就够了.

所以我们就判断一下, 如果这个标记的格子周围只有两个未标记的, 直接连边, 四个的话, 把四个 \(L\) 连起来, 注意, 是双向边.

\(code:\)

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
#define calc(i, j) (i - 1) * m + j
int read() {
  int x = 0, f = 1;
  char ch = getchar();
  for (; !isdigit(ch); ch = getchar()) if (ch == '-') f = -1;
  for (; isdigit(ch); ch = getchar()) x = (x << 1) + (x << 3) + (ch ^ 48);
  return x * f;
}
const int N = 505, M = 1e6 + 5;
int n, m;
int a[N][N], ans[N * N];
int tot, to[M], nxt[M], head[M];
char s[N][N];
void Add(int u, int v) {
  to[++tot] = v, nxt[tot] = head[u], head[u] = tot;
  to[++tot] = u, nxt[tot] = head[v], head[v] = tot;
}
bool Check(int i, int j, int k, int l) {
  if (!a[i][j] && !a[k][l]) return true;
  return false;
}
int Sum(int x, int y) {
  int sum = 0;
  if (!a[x - 1][y]) sum += ans[calc(x - 1, y)];
  if (!a[x][y - 1]) sum += ans[calc(x, y - 1)];
  if (!a[x][y + 1]) sum += ans[calc(x, y + 1)];
  if (!a[x + 1][y]) sum += ans[calc(x + 1, y)];
  return sum;
}
void DFS(int x, int fa) {
  ans[x] = 5 - ans[fa];
  for (int i = head[x]; i; i = nxt[i]) {
    int y = to[i];
    if (!ans[y]) DFS(y, x);
  }
}
int main() {
  n = read(), m = read(), ans[0] = 1;
  for (int i = 1; i <= n; i++) {
    scanf("%s", s[i] + 1);
    for (int j = 1; j <= m; j++) a[i][j] = s[i][j] == 'X';
  }
  for (int i = 2; i < n; i++) {
    for (int j = 2; j < m; j++) {
      if (a[i][j]) { //判断无解
        if (a[i - 1][j] + a[i][j - 1] + a[i][j + 1] + a[i + 1][j] & 1) {
          printf("NO");
          return 0;
        }
        if (Check(i - 1, j, i + 1, j) && !Check(i, j - 1, i, j + 1)) Add(calc(i - 1, j), calc(i + 1, j));
        else if (!Check(i - 1, j, i + 1, j) && Check(i, j - 1, i, j + 1)) Add(calc(i, j - 1), calc(i, j + 1));
        else {
          if (Check(i - 1, j, i, j + 1)) Add(calc(i - 1, j), calc(i, j + 1));
          if (Check(i, j + 1, i + 1, j)) Add(calc(i, j + 1), calc(i + 1, j));
          if (Check(i + 1, j, i, j - 1)) Add(calc(i + 1, j), calc(i, j - 1));
          if (Check(i, j - 1, i - 1, j)) Add(calc(i, j - 1), calc(i - 1, j));
        }
      }
    }
  }
  for (int i = 1; i <= n; i++) { //染色
    for (int j = 1; j <= m; j++) {
      if (!ans[calc(i, j)] && !a[i][j]) DFS(calc(i, j), 0);
    }
  }
  for (int i = 1; i <= n; i++) { //统计 marked cell 的答案
    for (int j = 1; j <= m; j++) {
      if (a[i][j]) {
        ans[calc(i, j)] = Sum(i, j);
      }
    }
  }
  printf("YES\n");
  for (int i = 1; i <= n; i++) {
    for (int j = 1; j <= m; j++) printf("%d ", ans[calc(i, j)]);
    printf("\n");
  }
  return 0;
}
posted @ 2021-09-27 18:11  sshadows  阅读(43)  评论(0编辑  收藏  举报