Submission #1324639

#TimeUsernameProblemLanguageResultExecution timeMemory
1324639jdsfdfConnect (CEOI06_connect)C++20
100 / 100
15 ms11416 KiB
#include <bits/stdc++.h>

using namespace std;

using i64 = int64_t;
#define el '\n'

int dp[2][8192];
short prv[12][40][8192];
char choice[12][40][8192];

void run_case(int tc) {
  int R, C;
  cin >> R >> C;
  string dummy;
  getline(cin, dummy);

  vector<string> g(R);
  for(int i = 0; i < R; ++i) {
    getline(cin, g[i]);
    while((int)g[i].size() < C) {
      g[i].push_back(' ');
    }
  }

  int N = R / 2;
  int M = C / 2;

  for(auto & i : dp)
    for(int & m : i)
      m = 1e9;

  dp[0][0] = 0;

  for (int c = 0; c < M; ++c) {    // column by column
    for (int r = 0; r < N; ++r) {     // dp[c][r][mask] is min cost if we have last mask boundary state
                                    // we must pass by 'mask' to go from processed rooms to unprocessed rooms
                                    // bit=1 : edge used
      int idx = c * N + r;
      int cur = idx % 2;
      int nxt = (idx + 1) % 2;

      for(int m = 0; m < (1 << (N + 1)); ++m) {
        dp[nxt][m] = 1e9;
      }

      for (int mask = 0; mask < (1 << (N + 1)); ++mask) {
        if (dp[cur][mask] >= 1e9) continue;

        int up = (mask >> r) & 1;       // got into (r, c) from above
        int le = (mask >> (r + 1)) & 1; // got into (r, c) from left

        for (int down = 0; down <= 1; ++down) {      // exit (r, c) from below
          if (down && (r == N - 1 || g[2 * r + 2][2 * c + 1] != ' ')) continue;

          for (int ri = 0; ri <= 1; ++ri) {              // exit (r, c) from right
            if (ri && (c == M - 1 || g[2 * r + 1][2 * c + 2] != ' ')) continue; // must be available

            int deg = up + le + down + ri;
            bool is_X = (g[2 * r + 1][2 * c + 1] == 'X');

            if (is_X && deg != 1) continue;
            if (!is_X && deg != 0 && deg != 2) continue;

            int new_mask = mask;
            new_mask &= ~(1 << r);          // remove edge in from above
            new_mask &= ~(1 << (r + 1));    // remove edge in from left
            new_mask |= (ri << r);          // edge right from (r, c)
            new_mask |= (down << (r + 1));  // edge down from (r, c), will be discarded if last row

            int nr = r + 1;
            int nc = c;
            int nmsk = new_mask;

            if (nr == N) {
              nr = 0;
              nc = c + 1;
              nmsk <<= 1;    // bit0 = 0 cuz no going down into (nr, nc), and bit1 is going right, but bitmax not needed now cuz no down from last row
            }

            if (nc == M && nmsk != 0) continue; // state not needed

            int cost = dp[cur][mask] + down + ri; // down and right edges out of (r, c)
            if (cost < dp[nxt][nmsk]) {
              dp[nxt][nmsk] = cost;
              // edges out of the cell we just processed
              choice[nr][nc][nmsk] = (char)((down << 1) | ri);
              prv[nr][nc][nmsk] = (short)mask;
            }
          }
        }
      }
    }
  }

  cout << dp[(M * N) % 2][0] * 2 << "\n";

  int cr = 0, cc = M, cmsk = 0;

  while (cr != 0 || cc != 0) {
    int r, c; // last processed (prv in loop, not in pipe)
    if (cr == 0) {
      r = N - 1;
      c = cc - 1;
    } else {
      r = cr - 1;
      c = cc;
    }

    int pmsk = prv[cr][cc][cmsk];  // came from dp[r][c][pmask]
    int ch = choice[cr][cc][cmsk]; // choice made by (r, c) to reach (rc, cc)
    // how we came in (cr, cc) from (r, c)
    int down = (ch >> 1) & 1;
    int ri = ch & 1;

    // where edges of (r, c) went
    if (down) g[2 * r + 2][2 * c + 1] = '.';
    if (ri) g[2 * r + 1][2 * c + 2] = '.';

    // how we go into of (r, c)
    int up = (pmsk >> r) & 1;
    int lef = (pmsk >> (r + 1)) & 1;

    // if edge out or in, then we must have passed in
    if ((up || lef || down || ri) && g[2 * r + 1][2 * c + 1] == ' ') {
      g[2 * r + 1][2 * c + 1] = '.';
    }

    cr = r;
    cc = c;
    cmsk = pmsk;
  }

  for(int i = 0; i < R; ++i) {
    while((int)g[i].size() > C && g[i].back() == ' ') {
      g[i].pop_back();
    }
    cout << g[i] << el;
  }
}

int32_t main() {
  ios::sync_with_stdio(0);
  cin.tie(0);
  cout.tie(0);
  int _t = 1;
//  cin >> _t;
  for (int i = 1; i <= _t; i++) {
    run_case(i);
  }
}
#Verdict Execution timeMemoryGrader output
Fetching results...