Problem:
Problem M: Fissure Puzzle Hard
Problem
$N \times N$個のマスから成るグリッドがある。最初すべてのマスは白色である。以下の手順に従って黒色のマスを増やしていく。
上から偶数番目かつ、左から偶数番目であるマスの中で、白色のマスを1つ選ぶ。選んだマスは黒色に変化する。さらに、そのマスの上下左右それぞれの方向について、隣接している白色のマスも連鎖的に黒色に変化する。この連鎖はその方向に白色のマスが存在しなくなるまで続く。(以下に例を示す)
□□□□□□□□□
□□□□□□□□□
□□□□□□□□□
□□□□□□□□□
□□□□□□□□□
□□□□□□□□□
□□□□□□□□□
□□□□□□□□□
□□□□□□□□□
↓上から4番目、左から6番目を選ぶ
□□□□□■□□□
□□□□□■□□□
□□□□□■□□□
■■■■■■■■■
□□□□□■□□□
□□□□□■□□□
□□□□□■□□□
□□□□□■□□□
□□□□□■□□□
↓上から2番目、左から2番目を選ぶ
□■□□□■□□□
■■■■■■□□□
□■□□□■□□□
■■■■■■■■■
□□□□□■□□□
□□□□□■□□□
□□□□□■□□□
□□□□□■□□□
□□□□□■□□□
↓上から6番目、左から8番目を選ぶ
□■□□□■□□□
■■■■■■□□□
□■□□□■□□□
■■■■■■■■■
□□□□□■□■□
□□□□□■■■■
□□□□□■□■□
□□□□□■□■□
□□□□□■□■□
あなたは上から$i$番目で左から$j$番目のマスの色が$A_{i,j}$であるグリッドを作りたい。
作ることが可能かどうかを判定せよ。可能な場合は、選ぶべきマスの場所と順番を求めよ。
Input
入力は以下の形式で与えられる。
$N$
$A_{1,1}$ $A_{1,2}$ ... $A_{1,N}$
$A_{2,1}$ $A_{2,2}$ ... $A_{2,N}$
...
$A_{N,1}$ $A_{N,2}$ ... $A_{N,N}$
$A_{i,j}$が'o'であるときは上から$i$番目、左から$j$番目のマスが白色であることを表し、'x'のときは黒色のマスであることを表す。
Constraints
入力は以下の条件を満たす。
$3 \le N \le 2047$
$N$は奇数である
$A_{i,j}$は'o'か'x'である
Output
不可能な場合は-1と1行に出力せよ。
  可能な場合は1行目に選ぶマスの個数を出力し、
  $i \times 2$行目には$i$番目に選択するマスが上から何番目なのかを、
  $i \times 2 + 1$行目には$i$番目に選択するマスが左から何番目なのかを出力せよ。
  一意に定まらない場合は辞書順で最小になるようにせよ。
Sample Input 1
5
oxooo
oxooo
oxooo
xxxxx
oxooo
Sample Output 1
1
4
2
Sample Input 2
9
oxoooooxo
oxxxxxxxx
oxoooooxo
xxxxxxxxx
oxoxooooo
oxxxxxxxx
oxoxoxooo
oxoxxxxxx
oxoxoxooo
Sample Output 2
4
4
2
2
8
6
4
8
6
Sample Input 3
3
oxx
oxx
ooo
Sample Output 3
-1

Submitted solutions:

code_snippet: #include <iostream>
#include <vector>
#include <queue>
#include <deque>
#include <unordered_map>
#include <tuple>

using namespace std;

struct Rect {
  int x;
  int y;
  int width;
  int height;
  int cross_x;
  int cross_y;
};

template<typename T>
struct RPN {
  deque<T> data;
  T& operator[](int i) {
    return data[data.size() - i - 1];
  }
  void push(T x) {
    data.push_back(x);
  }
  void pop(int n) {
    for (int i = 0; i < n; ++i) {
      data.pop_back();
    }
  }
  int size() {
    return data.size();
  }
};

bool get_tile(vector<char>& A, int N, int x, int y, int& width, int& height) {
  if (x % 2 != 0 || y % 2 != 0) {
    return false;
  }
  int w = N - x;
  int h = N - y;
  for (int i = x; i < N; ++i) {
    if (A[i + N * y] == 'x') {
      w = i - x;
      break;
    }
  }
  for (int i = y; i < N; ++i) {
    if (A[x + N * i] == 'x') {
      h = i - y;
      break;
    }
  }
  if (y + h < N) {
    for (int i = x; i < x + w; ++i) {
      if (A[i + N * (y + h)] == 'o') {
        return false;
      }
    }
  }
  if (x + w < N) {
    for (int i = y; i < y + h; ++i) {
      if (A[x + w + N * i] == 'o') {
        return false;
      }
    }
  }
  if (y + h < N && x + w < N) {
    if (A[x + w + N * (y + h)] == 'o') {
      return false;
    }
  }
  for (int i = x + 1; i < x + w; ++i) {
    for (int j = y + 1; j < y + h; ++j) {
      if (A[i + N * j] == 'x') {
        return false;
      }
    }
  }
  width = w;
  height = h;
  return true;
}

int main() {
  int N;
  cin >> N;
  vector<char> A(N * N);
  unordered_map<int, pair<int, int>> rects;
  queue<tuple<int, int, int, int>> q;
  for (int j = 0; j < N; ++j) {
    for (int i = 0; i < N; ++i) {
      cin >> A[i + N * j];
    }
  }
  int width;
  int height;
  if (!get_tile(A, N, 0, 0, width, height)) {
    cout << -1 << endl;
    return 0;
  }
  q.emplace(0, 0, width, height);
  rects.emplace(0, make_pair(width, height));
  while (!q.empty()) {
    tuple<int, int, int, int> rect = q.front();
    int x = get<0>(rect);
    int y = get<1>(rect);
    int w = get<2>(rect);
    int h = get<3>(rect);
    q.pop();
    if (w != 0 && h != 0) {
//       cout << x << ", " << y << ", " << w << ", " << h << endl;
    }
    rects.emplace(x + 10000 * y, make_pair(w, h));
    if (x + w < N && rects.find((x + w + 1) + 10000 * y) == rects.end()) {
      if (!get_tile(A, N, x + w + 1, y, width, height)) {
        cout << -1 << endl;
        return 0;
      }
      q.emplace(x + w + 1, y, width, height);
      rects.emplace((x + w + 1) + 10000 * y, make_pair(width, height));
    }
    if (y + h < N && rects.find(x + 10000 * (y + h + 1)) == rects.end()) {
      if (!get_tile(A, N, x, y + h + 1, width, height)) {
        cout << -1 << endl;
        return 0;
      }
      q.emplace(x, y + h + 1, width, height);
      rects.emplace(x + 10000 * (y + h + 1), make_pair(width, height));
    }
  }
  unordered_map<int, vector<int>> tree;
  RPN<pair<Rect, int>> rpn;
  if (rects[0].first == N && rects[0].second == N) {
    cout << 0 << endl;
    return 0;
  }
  rpn.push(make_pair(Rect {0, 0, rects[0].first, rects[0].second, -1, -1}, 0));
  int merge_count = 0;
  while (true) {
    int type = rpn[0].second;
    if (type == 3) {
      if (rpn[0].first.width != rpn[3].first.width ||
          rpn[1].first.width != rpn[2].first.width ||
          rpn[2].first.height != rpn[3].first.height ||
          rpn[0].first.height != rpn[1].first.height) {
        cout << -1 << endl;
        return 0;
      }
      int new_x = rpn[3].first.x;
      int new_y = rpn[3].first.y;
      int new_w = rpn[3].first.width + rpn[2].first.width + 1;
      int new_h = rpn[3].first.height + rpn[0].first.height + 1;
      int cross_x = rpn[1].first.x - 1;
      int cross_y = rpn[1].first.y - 1;
      vector<int> children;
      if (rpn[0].first.cross_x != -1) {
        children.emplace_back(rpn[0].first.cross_x + 10000 * rpn[0].first.cross_y);
      }
      if (rpn[1].first.cross_x != -1) {
        children.emplace_back(rpn[1].first.cross_x + 10000 * rpn[1].first.cross_y);
      }
      if (rpn[2].first.cross_x != -1) {
        children.emplace_back(rpn[2].first.cross_x + 10000 * rpn[2].first.cross_y);
      }
      if (rpn[3].first.cross_x != -1) {
        children.emplace_back(rpn[3].first.cross_x + 10000 * rpn[3].first.cross_y);
      }
      tree.emplace((rpn[1].first.x - 1) + 10000 * (rpn[1].first.y - 1), children);
      rpn.pop(4);
      rpn.push(make_pair(Rect {new_x, new_y, new_w, new_h, cross_x, cross_y}, -1));
      ++merge_count;
//       cout << "merge: (" << new_x << ", " << new_y << ", " << new_w << ", " << new_h << ")" << endl;
    } else if (type == 2) {
      int x = rpn[2].first.x;
      int y = rpn[2].first.y + rpn[2].first.height + 1;
      if (y >= N) {
        cout << -1 << endl;
        return 0;
      }
      int w = rects[x + 10000 * y].first;
      int h = rects[x + 10000 * y].second;
      rpn.push(make_pair(Rect {x, y, w, h, -1, -1}, -1));
//       cout << "add: (" << x << ", " << y << ", " << w << ", " << h << ")" << endl;
    } else if (type == 1) {
      int x = rpn[0].first.x;
      int y = rpn[0].first.y + rpn[0].first.height + 1;
      if (y >= N) {
        cout << -1 << endl;
        return 0;
      }
      int w = rects[x + 10000 * y].first;
      int h = rects[x + 10000 * y].second;
      rpn.push(make_pair(Rect {x, y, w, h, -1, -1}, -1));
//       cout << "add: (" << x << ", " << y << ", " << w << ", " << h << ")" << endl;
    } else if (type == 0) {
      int x = rpn[0].first.x + rpn[0].first.width + 1;
      if (x >= N) {
        cout << -1 << endl;
        return 0;
      }
      int y = rpn[0].first.y;
      int w = rects[x + 10000 * y].first;
      int h = rects[x + 10000 * y].second;
      rpn.push(make_pair(Rect {x, y, w, h, -1, -1}, -1));
//       cout << "add: (" << x << ", " << y << ", " << w << ", " << h << ")" << endl;
    } else {
      if (rpn.size() == 1) {
        if (rpn[0].first.width == N && rpn[0].first.height == N) {
          break;
        } else {
          rpn[0].second = 0;
        }
      } else {
        int prevtype = rpn[1].second;
        if (prevtype == 2) {
          if (rpn[0].first.height < rpn[1].first.height) {
            rpn[0].second = 0;
          } else {
            rpn[0].second = 3;
          }
        } else if (prevtype == 1) {
          if (rpn[0].first.width < rpn[1].first.width) {
            rpn[0].second = 0;
          } else {
            rpn[0].second = 2;
          }
        } else if (prevtype == 0) {
          if (rpn[0].first.height < rpn[1].first.height) {
            rpn[0].second = 0;
          } else {
            rpn[0].second = 1;
          }
        }
      }
    }
  }
  priority_queue<int, vector<int>, std::greater<int>> pq;
  pq.push(rpn[0].first.cross_x + 10000 * rpn[0].first.cross_y);
  cout << merge_count << endl;
  while (!pq.empty()) {
    int cross = pq.top();
    pq.pop();
    for (int child_cross : tree[cross]) {
      pq.push(child_cross);
    }
    cout << (cross / 10000 + 1) << endl;
    cout << (cross % 10000 + 1) << endl;
  }
}
accuracy: 1
time_ms: 1180
memory_kb: 71652
final_rank: 2

code_snippet: #include <iostream>
#include <vector>
#include <queue>
#include <deque>
#include <unordered_map>
#include <tuple>

using namespace std;

struct Rect {
  int x;
  int y;
  int width;
  int height;
  int cross_x;
  int cross_y;
};

template<typename T>
struct RPN {
  deque<T> data;
  T& operator[](int i) {
    return data[data.size() - i - 1];
  }
  void push(T x) {
    data.push_back(x);
  }
  void pop(int n) {
    for (int i = 0; i < n; ++i) {
      data.pop_back();
    }
  }
  int size() {
    return data.size();
  }
};

bool get_tile(vector<char>& A, int N, int x, int y, int& width, int& height) {
  if (x % 2 != 0 || y % 2 != 0) {
    return false;
  }
  int w = N - x;
  int h = N - y;
  for (int i = x; i < N; ++i) {
    if (A[i + N * y] == 'x') {
      w = i - x;
      break;
    }
  }
  for (int i = y; i < N; ++i) {
    if (A[x + N * i] == 'x') {
      h = i - y;
      break;
    }
  }
  if (y + h < N) {
    for (int i = x; i < x + w; ++i) {
      if (A[i + N * (y + h)] == 'o') {
        return false;
      }
    }
  }
  if (x + w < N) {
    for (int i = y; i < y + h; ++i) {
      if (A[x + w + N * i] == 'o') {
        return false;
      }
    }
  }
  if (y + h < N && x + w < N) {
    if (A[x + w + N * (y + h)] == 'o') {
      return false;
    }
  }
  for (int i = x + 1; i < x + w; ++i) {
    for (int j = y + 1; j < y + h; ++j) {
      if (A[i + N * y] == 'x') {
        return false;
      }
    }
  }
  width = w;
  height = h;
  return true;
}

int main() {
  int N;
  cin >> N;
  vector<char> A(N * N);
  unordered_map<int, pair<int, int>> rects;
  queue<tuple<int, int, int, int>> q;
  for (int j = 0; j < N; ++j) {
    for (int i = 0; i < N; ++i) {
      cin >> A[i + N * j];
    }
  }
  int width;
  int height;
  if (!get_tile(A, N, 0, 0, width, height)) {
    cout << -1 << endl;
    return 0;
  }
  q.emplace(0, 0, width, height);
  rects.emplace(0, make_pair(width, height));
  while (!q.empty()) {
    tuple<int, int, int, int> rect = q.front();
    int x = get<0>(rect);
    int y = get<1>(rect);
    int w = get<2>(rect);
    int h = get<3>(rect);
    q.pop();
    if (w != 0 && h != 0) {
//       cout << x << ", " << y << ", " << w << ", " << h << endl;
    }
    rects.emplace(x + 10000 * y, make_pair(w, h));
    if (x + w < N && rects.find((x + w + 1) + 10000 * y) == rects.end()) {
      if (!get_tile(A, N, x + w + 1, y, width, height)) {
        cout << -1 << endl;
        return 0;
      }
      q.emplace(x + w + 1, y, width, height);
      rects.emplace((x + w + 1) + 10000 * y, make_pair(width, height));
    }
    if (y + h < N && rects.find(x + 10000 * (y + h + 1)) == rects.end()) {
      if (!get_tile(A, N, x, y + h + 1, width, height)) {
        cout << -1 << endl;
        return 0;
      }
      q.emplace(x, y + h + 1, width, height);
      rects.emplace(x + 10000 * (y + h + 1), make_pair(width, height));
    }
  }
  unordered_map<int, vector<int>> tree;
  RPN<pair<Rect, int>> rpn;
  if (rects[0].first == N && rects[0].second == N) {
    cout << 0 << endl;
    return 0;
  }
  rpn.push(make_pair(Rect {0, 0, rects[0].first, rects[0].second, -1, -1}, 0));
  int merge_count = 0;
  while (true) {
    int type = rpn[0].second;
    if (type == 3) {
      if (rpn[0].first.width != rpn[3].first.width ||
          rpn[1].first.width != rpn[2].first.width ||
          rpn[2].first.height != rpn[3].first.height ||
          rpn[0].first.height != rpn[1].first.height) {
        cout << -1 << endl;
        return 0;
      }
      int new_x = rpn[3].first.x;
      int new_y = rpn[3].first.y;
      int new_w = rpn[3].first.width + rpn[2].first.width + 1;
      int new_h = rpn[3].first.height + rpn[0].first.height + 1;
      int cross_x = rpn[1].first.x - 1;
      int cross_y = rpn[1].first.y - 1;
      vector<int> children;
      if (rpn[0].first.cross_x != -1) {
        children.emplace_back(rpn[0].first.cross_x + 10000 * rpn[0].first.cross_y);
      }
      if (rpn[1].first.cross_x != -1) {
        children.emplace_back(rpn[1].first.cross_x + 10000 * rpn[1].first.cross_y);
      }
      if (rpn[2].first.cross_x != -1) {
        children.emplace_back(rpn[2].first.cross_x + 10000 * rpn[2].first.cross_y);
      }
      if (rpn[3].first.cross_x != -1) {
        children.emplace_back(rpn[3].first.cross_x + 10000 * rpn[3].first.cross_y);
      }
      tree.emplace((rpn[1].first.x - 1) + 10000 * (rpn[1].first.y - 1), children);
      rpn.pop(4);
      rpn.push(make_pair(Rect {new_x, new_y, new_w, new_h, cross_x, cross_y}, -1));
      ++merge_count;
//       cout << "merge: (" << new_x << ", " << new_y << ", " << new_w << ", " << new_h << ")" << endl;
    } else if (type == 2) {
      int x = rpn[2].first.x;
      int y = rpn[2].first.y + rpn[2].first.height + 1;
      if (y >= N) {
        cout << -1 << endl;
        return 0;
      }
      int w = rects[x + 10000 * y].first;
      int h = rects[x + 10000 * y].second;
      rpn.push(make_pair(Rect {x, y, w, h, -1, -1}, -1));
//       cout << "add: (" << x << ", " << y << ", " << w << ", " << h << ")" << endl;
    } else if (type == 1) {
      int x = rpn[0].first.x;
      int y = rpn[0].first.y + rpn[0].first.height + 1;
      if (y >= N) {
        cout << -1 << endl;
        return 0;
      }
      int w = rects[x + 10000 * y].first;
      int h = rects[x + 10000 * y].second;
      rpn.push(make_pair(Rect {x, y, w, h, -1, -1}, -1));
//       cout << "add: (" << x << ", " << y << ", " << w << ", " << h << ")" << endl;
    } else if (type == 0) {
      int x = rpn[0].first.x + rpn[0].first.width + 1;
      if (x >= N) {
        cout << -1 << endl;
        return 0;
      }
      int y = rpn[0].first.y;
      int w = rects[x + 10000 * y].first;
      int h = rects[x + 10000 * y].second;
      rpn.push(make_pair(Rect {x, y, w, h, -1, -1}, -1));
//       cout << "add: (" << x << ", " << y << ", " << w << ", " << h << ")" << endl;
    } else {
      if (rpn.size() == 1) {
        if (rpn[0].first.width == N && rpn[0].first.height == N) {
          break;
        } else {
          rpn[0].second = 0;
        }
      } else {
        int prevtype = rpn[1].second;
        if (prevtype == 2) {
          if (rpn[0].first.height < rpn[1].first.height) {
            rpn[0].second = 0;
          } else {
            rpn[0].second = 3;
          }
        } else if (prevtype == 1) {
          if (rpn[0].first.width < rpn[1].first.width) {
            rpn[0].second = 0;
          } else {
            rpn[0].second = 2;
          }
        } else if (prevtype == 0) {
          if (rpn[0].first.height < rpn[1].first.height) {
            rpn[0].second = 0;
          } else {
            rpn[0].second = 1;
          }
        }
      }
    }
  }
  priority_queue<int, vector<int>, std::greater<int>> pq;
  pq.push(rpn[0].first.cross_x + 10000 * rpn[0].first.cross_y);
  cout << merge_count << endl;
  while (!pq.empty()) {
    int cross = pq.top();
    pq.pop();
    for (int child_cross : tree[cross]) {
      pq.push(child_cross);
    }
    cout << (cross / 10000 + 1) << endl;
    cout << (cross % 10000 + 1) << endl;
  }
}
accuracy: 0.08064516129032258
time_ms: 160
memory_kb: 7040
final_rank: 7

code_snippet: #include <iostream>
#include <vector>
#include <queue>
#include <algorithm>
#include <unordered_map>
#include <tuple>

using namespace std;

bool select(const vector<tuple<int, int, int>> &line_ns, int line_ns_st,
            const vector<tuple<int, int, int>> &line_ew, int line_ew_st,
            int x, int y, int width, int height, int N,
            int px, int py, vector<tuple<int, int, int, int>> &results) {
  int result_x = -1;
  int result_y = -1;
  int line_ns_st_next = line_ns_st;
  int line_ew_st_next = line_ew_st;
  if (width == 0 || height == 0) {
    return true;
  }
  bool white = true;
  for (int i = line_ns_st; i < line_ns.size(); ++i) {
    if (get<2>(line_ns[i]) >= x + width) {
      break;
    }
    if (!(y + height <= get<0>(line_ns[i]) || get<1>(line_ns[i]) <= y)) {
      white = false;
    }
    if (get<0>(line_ns[i]) <= y && y + height <= get<1>(line_ns[i])) {
      result_x = get<2>(line_ns[i]);
      line_ns_st_next = i + 1;
      for (int i = line_ew_st; i < line_ew.size(); ++i) {
        if (get<2>(line_ew[i]) >= y + height) {
          break;
        }
        if (get<0>(line_ew[i]) <= x && x + width <= get<1>(line_ew[i])) {
          result_y = get<2>(line_ew[i]);
          line_ew_st_next = i + 1;
          vector<tuple<int, int, int, int>> child_results;
          bool ok = select(line_ns, line_ns_st, line_ew, line_ew_st, x, y, result_x - x, result_y - y, N, result_x, result_y, child_results) &&
                    select(line_ns, line_ns_st, line_ew, line_ew_st_next, x, result_y + 1, result_x - x, height - (result_y - y) - 1, N, result_x, result_y, child_results) &&
                    select(line_ns, line_ns_st_next, line_ew, line_ew_st, result_x + 1, y, width - (result_x - x) - 1, result_y - y, N, result_x, result_y, child_results) &&
                    select(line_ns, line_ns_st_next, line_ew, line_ew_st_next, result_x + 1, result_y + 1, width - (result_x - x) - 1, height - (result_y - y) - 1, N, result_x, result_y, child_results);
          if (ok) {
            results.emplace_back(result_x, result_y, px, py);
            for (auto child_result : child_results) {
              results.emplace_back(child_result);
            }
            return true;
          }
        }
      }
    }
  }
  if (white) {
    return true;
  }
  return false;
}

int main() {
  int N;
  cin >> N;
  vector<char> A(N * N);
  for (int j = 0; j < N; ++j) {
    for (int i = 0; i < N; ++i) {
      cin >> A[i + N * j];
    }
  }
  vector<tuple<int, int, int>> line_ns;
  vector<tuple<int, int, int>> line_ew;
  for (int j = 0; j < N; ++j) {
    int st = -1;
    for (int i = 0; i < N; ++i) {
      if (A[i + N * j] == 'x') {
        if (st == -1) {
          st = i;
        }
      } else if (st != -1) {
        line_ew.emplace_back(st, i, j);
        st = -1;
      }
    }
    if (st != -1) {
      line_ew.emplace_back(st, N, j);
    }
  }
  for (int i = 0; i < N; ++i) {
    int st = -1;
    for (int j = 0; j < N; ++j) {
      if (A[i + N * j] == 'x') {
        if (st == -1) {
          st = j;
        }
      } else if (st != -1) {
        line_ns.emplace_back(st, j, i);
        st = -1;
      }
    }
    if (st != -1) {
      line_ns.emplace_back(st, N, i);
    }
  }
  vector<tuple<int, int, int, int>> results;
  if (!select(line_ns, 0,
              line_ew, 0,
              0, 0, N, N, N, -1, -1, results)) {
    cout << -1 << endl;
    return 0;
  };
  unordered_map<int, vector<pair<int, int>>> result_map;
  for (auto result : results) {
    int k = get<2>(result) + 10000 * get<3>(result);
    if (result_map.find(k) == result_map.end()) {
      result_map.emplace(k, vector<pair<int, int>> {});
    }
    result_map[k].emplace_back(make_pair(get<0>(result), get<1>(result)));
  }
  auto comp = [](const pair<int, int> &a, const pair<int, int> &b) { if (a.second == b.second) { return a.first > b.first; } else { return a.second > b.second; } };
  priority_queue<pair<int, int>, vector<pair<int, int>>, decltype(comp)> pq(comp);
  if (result_map.find(-1 + 10000 * (-1)) == result_map.end()) {
    cout << 0 << endl;
    return 0;
  }
  pq.push(result_map[-1 + 10000 * (-1)][0]);
  cout << results.size() << endl;
  while (!pq.empty()) {
    auto data = pq.top();
    pq.pop();
    cout << (data.second + 1) << endl;
    cout << (data.first + 1) << endl;
    int k = data.first + 10000 * data.second;
    if (result_map.find(k) != result_map.end()) {
      for (auto result : result_map[k]) {
        pq.push(result);
      }
    }
  }
  return 0;
}
accuracy: 0.6612903225806451
time_ms: 190
memory_kb: 37520
final_rank: 4

code_snippet: #include <iostream>
#include <vector>
#include <queue>
#include <algorithm>
#include <unordered_map>
#include <tuple>

using namespace std;

bool select(const vector<tuple<int, int, int>> &line_ns, int line_ns_st,
            const vector<tuple<int, int, int>> &line_ew, int line_ew_st,
            int x, int y, int width, int height, int N,
            int px, int py, vector<tuple<int, int, int, int>> &results) {
  int result_x = -1;
  int result_y = -1;
  int line_ns_st_next = line_ns_st;
  int line_ew_st_next = line_ew_st;
  if (width == 0 || height == 0) {
    return true;
  }
  bool white = true;
  for (int i = line_ns_st; i < line_ns.size(); ++i) {
    if (get<2>(line_ns[i]) >= x + width) {
      break;
    }
    if (!(y + height <= get<0>(line_ns[i]) || get<1>(line_ns[i]) <= y)) {
      white = false;
    }
    if (get<0>(line_ns[i]) <= y && y + height <= get<1>(line_ns[i])) {
      result_x = get<2>(line_ns[i]);
      line_ns_st_next = i + 1;
      for (int i = line_ew_st; i < line_ew.size(); ++i) {
        if (get<2>(line_ew[i]) >= y + height) {
          break;
        }
        if (get<0>(line_ew[i]) <= x && x + width <= get<1>(line_ew[i])) {
          result_y = get<2>(line_ew[i]);
          line_ew_st_next = i + 1;
          vector<tuple<int, int, int, int>> child_results;
          bool ok = select(line_ns, line_ns_st, line_ew, line_ew_st, x, y, result_x - x, result_y - y, N, result_x, result_y, child_results) &&
                    select(line_ns, line_ns_st, line_ew, line_ew_st_next, x, result_y + 1, result_x - x, height - (result_y - y) - 1, N, result_x, result_y, child_results) &&
                    select(line_ns, line_ns_st_next, line_ew, line_ew_st, result_x + 1, y, width - (result_x - x) - 1, result_y - y, N, result_x, result_y, child_results) &&
                    select(line_ns, line_ns_st_next, line_ew, line_ew_st_next, result_x + 1, result_y + 1, width - (result_x - x) - 1, height - (result_y - y) - 1, N, result_x, result_y, child_results);
          if (ok) {
            results.emplace_back(result_x, result_y, px, py);
            for (auto child_result : child_results) {
              results.emplace_back(child_result);
            }
            return true;
          }
        }
      }
    }
  }
  if (white) {
    return true;
  }
  return false;
}

int main() {
  int N;
  cin >> N;
  vector<char> A(N * N);
  for (int j = 0; j < N; ++j) {
    for (int i = 0; i < N; ++i) {
      cin >> A[i + N * j];
    }
  }
  vector<tuple<int, int, int>> line_ns;
  vector<tuple<int, int, int>> line_ew;
  for (int j = 0; j < N; ++j) {
    int st = -1;
    for (int i = 0; i < N; ++i) {
      if (A[i + N * j] == 'x') {
        if (st == -1) {
          st = i;
        }
      } else if (st != -1) {
        line_ew.emplace_back(st, i, j);
        st = -1;
      }
    }
    if (st != -1) {
      line_ew.emplace_back(st, N, j);
    }
  }
  for (int i = 0; i < N; ++i) {
    int st = -1;
    for (int j = 0; j < N; ++j) {
      if (A[i + N * j] == 'x') {
        if (st == -1) {
          st = j;
        }
      } else if (st != -1) {
        line_ns.emplace_back(st, j, i);
        st = -1;
      }
    }
    if (st != -1) {
      line_ns.emplace_back(st, N, i);
    }
  }
  vector<tuple<int, int, int, int>> results;
  if (!select(line_ns, 0,
              line_ew, 0,
              0, 0, N, N, N, -1, -1, results)) {
    cout << -1 << endl;
    return 0;
  };
  unordered_map<int, vector<pair<int, int>>> result_map;
  for (auto result : results) {
    int k = get<2>(result) + 10000 * get<3>(result);
    if (result_map.find(k) == result_map.end()) {
      result_map.emplace(k, vector<pair<int, int>> {});
    }
    result_map[k].emplace_back(make_pair(get<0>(result), get<1>(result)));
  }
  auto comp = [](const pair<int, int> &a, const pair<int, int> &b) { if (a.second == b.second) { return a.first > b.first; } else { return a.second > b.second; } };
  priority_queue<pair<int, int>, vector<pair<int, int>>, decltype(comp)> pq(comp);
  pq.push(result_map[-1 + 10000 * (-1)][0]);
  cout << results.size() << endl;
  while (!pq.empty()) {
    auto data = pq.top();
    pq.pop();
    cout << (data.second + 1) << endl;
    cout << (data.first + 1) << endl;
    int k = data.first + 10000 * data.second;
    if (result_map.find(k) != result_map.end()) {
      for (auto result : result_map[k]) {
        pq.push(result);
      }
    }
  }
  return 0;
}
accuracy: 0.5967741935483871
time_ms: 180
memory_kb: 37516
final_rank: 6

code_snippet: #include<bits/stdc++.h>
using namespace std;
typedef pair<int,int> P;
#define MAX 2050

int N;
char t[MAX][MAX];
bool T[MAX][MAX];
int a[MAX][MAX];
int b[MAX][MAX];

map < P , vector<P> > G;

bool inField(int y,int x){
  return (0<=y&&y<N&&0<=x&&x<N);
}

bool inField(P p){
  return inField(p.first,p.second);
}

bool inField(int ay,int ax,int by,int bx,P p){
  int y=p.first;
  int x=p.second;
  return (ay<y&&y<by&&ax<x&&x<bx);
}

map< P , P > mem[4];

P search(P p,int dir){
  if(mem[dir].count(p))return mem[dir][p];
  int Dy[]={-1,-1,1,1};
  int Dx[]={-1,1,1,-1};
  int dy=Dy[dir];
  int dx=Dx[dir];
  int y=p.first+dy;
  int x=p.second+dx;
  while(inField(y+dy,x)&&t[y+dy][x]=='o')y+=dy;
  while(inField(y,x+dx)&&t[y][x+dx]=='o')x+=dx;
  return mem[dir][p]=P(y+dy,x+dx);
}

void put(P p,int dir){
  int y=p.first;
  int x=p.second;
  int dy[]={-1,0,1,0};
  int dx[]={0,1,0,-1};
  T[y][x]=false;
  while(inField(y,x)&&!T[y][x]){
    T[y][x]=true;
    y+=dy[dir];
    x+=dx[dir];
  }
}


set< P > st;

P solve(int ay,int ax,int by,int bx){
  P sp=P(-1,-1);
  P tmp=P(ay,ax);
  while(1){
    if(mem[2].count(tmp))break;
    tmp=search(tmp,2);
    if(!inField(ay,ax,by,bx,tmp))break;
    if(st.count(tmp)){
      sp=tmp;
    }
    st.insert(tmp);
  }
  tmp=P(by,ax);
  while(1){
    if(mem[1].count(tmp))break;
    tmp=search(tmp,1);
    if(!inField(ay,ax,by,bx,tmp))break;
    if(st.count(tmp)){
      sp=tmp;
    }
    st.insert(tmp);
  }
  if(sp.first==-1)return P(-1,-1);
  if(sp.first<=ay || sp.second<=ax)return P(-1,-1);
  if(sp.first>=by || sp.second>=bx)return P(-1,-1);
  P LU=solve(ay,ax,sp.first,sp.second);
  P LD=solve(sp.first,ax,by,sp.second);
  P RU=solve(ay,sp.second,sp.first,bx);
  P RD=solve(sp.first,sp.second,by,bx);
  if(LU.first!=-1)G[ sp ].push_back(LU);
  if(LD.first!=-1)G[ sp ].push_back(LD);
  if(RU.first!=-1)G[ sp ].push_back(RU);
  if(RD.first!=-1)G[ sp ].push_back(RD);
  return sp;
}

int main(){
  

  scanf("%d",&N);
  bool flag=false;
  for(int i=0;i<N;i++){
    scanf("%s",t[i]);
    for(int j=0;j<N;j++)
      if(t[i][j]=='x')flag=true;
  }
  if(!flag){
    cout<<0<<endl;
    return 0;
  }
  
  P sp=solve(-1,-1,N,N);

  map<P,bool> flg;
  priority_queue< P , vector<P> , greater<P> > Q;
  flg[ sp ]=true;
  Q.push( sp );
  
  vector<P> ans;
  while(!Q.empty()){
    P p=Q.top();

    Q.pop();
    ans.push_back(p);

    if(T[p.first][p.second]){
      printf("-1\n");
      return 0;
    }
    
    for(int i=0;i<4;i++){
      put(p,i);
    }
        
    for(int i=0;i<(int)G[p].size();i++){
      P to=G[p][i];
      if(to==P(-1,-1))continue;
      if(flg[to])continue;
      if(!inField(to))continue;
      flg[to]=true;
      Q.push(to);
    }
  }

  for(int i=0;i<N;i++){
    for(int j=0;j<N;j++){
      if( (t[i][j]=='x') != T[i][j] ){
        printf("-1\n");
        return 0;
      }
    }
  }

  printf("%d\n",(int)ans.size());
  for(int i=0;i<(int)ans.size();i++){
    printf("%d\n",ans[i].first+1);
    printf("%d\n",ans[i].second+1);
  }
  return 0;
}
accuracy: 1
time_ms: 1240
memory_kb: 214416
final_rank: 3

code_snippet: #include<bits/stdc++.h>
using namespace std;

typedef pair<int,int> P;

#define fi first
#define se second

#define MAX 2055

char s[MAX][MAX];

int n;

int dx1[]={0,0,1,-1};
int dy1[]={1,-1,0,0};
int dx2[]={1,-1};
int dy2[]={1,1};

int color[MAX][MAX];
int table[MAX][MAX];
int cnt[MAX][MAX];

bool used[2][MAX][MAX];

map<P,vector<P> >Tree;

vector<P>ans;

void BAD_END(){
	cout<<-1<<endl;
	exit(0);
}

void Input(){
	cin>>n;
	for(int i=0;i<n;i++){
		scanf("%s",s[i]);
	}
}

bool in(int a,int b){
	return !(a<0||a>=n||b<0||b>=n);
}

bool in2(int a,int b,pair<P,P> c){
	return !(c.fi.se>a||c.se.se<a||c.fi.fi>b||c.se.fi<b);
}

void area_paint(int x,int y,int k){
	queue<P>q;
	q.push(P(x,y));
	color[y][x]=k;
	while(!q.empty()){
		P p=q.front();q.pop();
		y=p.se;
		x=p.fi;
	    for(int i=0;i<4;i++){
		    int x1=x+dx1[i];
		    int y1=y+dy1[i];
		    if(in(x1,y1)&&s[y1][x1]=='o'&&!color[y1][x1]){
			    q.push(P(x1,y1));
			    color[y1][x1]=k;
		    }
	    }
	}
}

void pre_fill(){
	int k=1;
	for(int i=0;i<n;i++){
		for(int j=0;j<n;j++){
			if(s[i][j]=='o'&&!color[i][j]){
				area_paint(j,i,k++);
			}
		}
	}
}

P get_center(P p,int k,pair<P,P> v){
	P cent=P(-1,-1);
	int y=p.se,Y=p.se,p1;
	int x=p.fi,X=p.fi,p2;

	while(1){

	    while(used[k][y][x]){
	    	return P(-1,-1);
	    }

	    while(1){
		    if(in(y,x)&&s[y][x]=='o'){
			    y+=dy2[k];
		    }
		    else break;
	    }
	    y-=dy2[k];

	    while(1){
		    if(in(y,x)&&s[y][x]=='o'){
			    x+=dx2[k];
		    }
		    else break;
	    }
	    y+=dy2[k];

	    if(!in2(y,x,v)) break;

	    used[k][Y][X]=1;
	    cnt[y][x]++;
	    Y=y+dy2[k],X=x+dx2[k];

	    if(cnt[y][x]==2) cent=P(x,y);

	    y+=dy2[k];
	    x+=dx2[k];

	    //if(!in2(y,x,v)) break;
	}

	return cent;
}
P make_tree(int x1,int y1,int x2,int y2){

	if(color[y1][x1]==color[y2][x2])return P(-1,-1);

	P center;
	P tmp[4];
	pair<P,P>p;

	p=make_pair(P(x1,y1),P(x2,y2));

	tmp[0]=P(x1,y1);
	tmp[1]=P(x2,y1);
	tmp[2]=P(-1,-1);
	tmp[3]=P(-1,-1);

	for(int i=0;i<2;i++){
		center=get_center(tmp[i],i,p);
		if(center.fi!=-1){
			break;
		}
		tmp[i]=P(-1,-1);
	}

	if(center.fi!=-1)tmp[0]=make_tree(x1,y1,center.fi-1,center.se-1);
	if(center.fi!=-1)tmp[1]=make_tree(center.fi+1,y1,x2,center.se-1);
	if(center.fi!=-1)tmp[2]=make_tree(x1,center.se+1,center.fi-1,y2);
	if(center.fi!=-1)tmp[3]=make_tree(center.fi+1,center.se+1,x2,y2);

	for(int i=0;i<4;i++){
		Tree[center].push_back(tmp[i]);
	}

	return center;
}

void priority_sort(P center){

	priority_queue<P,vector<P>,greater<P> >q;
	q.push(P(center.se,center.fi));

	while(!q.empty()){

		center=q.top();q.pop();
		if(center.fi==-1)continue;

		ans.push_back(center);

		for(int i=0;i<Tree[P(center.se,center.fi)].size();i++){
			q.push(P(Tree[P(center.se,center.fi)][i].se,Tree[P(center.se,center.fi)][i].fi));
		}
	}
}

void cross_fill(P p){
	for(int i=0;i<4;i++){
		int y=p.fi;
		int x=p.se;
		while(1){
			y+=dy1[i];
			x+=dx1[i];
			if(in(y,x)&&s[y][x]=='x'&&!table[y][x]){
				table[y][x]=1;
			}
			else if(table[y][x]&&in(y,x)) break;
			else if(s[y][x]=='o'&&in(y,x)){
				BAD_END();
			}
			else break;
		}
	}
	table[p.fi][p.se]=1;
}

void fill_table(){
	for(int i=0;i<ans.size();i++){
		cross_fill(ans[i]);
	}
}

void error_check(){
	for(int i=0;i<n;i++){
		for(int j=0;j<n;j++){
			if(s[i][j]=='x'&&!table[i][j]){
				BAD_END();
			}
		}
	}
}

void Output(){

	cout<<ans.size()<<endl;

	for(int i=0;i<ans.size();i++){
		printf("%d\n%d\n",ans[i].fi+1,ans[i].se+1);
	}
}

main(){
	P center;
	Input();
	pre_fill();
	center=make_tree(0,0,n-1,n-1);
	priority_sort(center);
	fill_table();
	error_check();
	Output();
}
accuracy: 1
time_ms: 710
memory_kb: 102760
final_rank: 1

code_snippet: // need
#include <iostream>
#include <algorithm>

// data structure
#include <bitset>
//#include <list>
#include <map>
#include <queue>
#include <set>
#include <stack>
#include <string>
#include <utility>
#include <vector>
#include <array>
//#include <tuple>
//#include <unordered_map>
#include <unordered_set>
#include <complex>
//#include <deque>
#include<valarray>

// stream
//#include <istream>
//#include <sstream>
//#include <ostream>
//#include <fstream>

// etc
#include <cmath>
#include <cassert>
#include <functional>
#include <iomanip>
//#include <typeinfo>
#include <chrono>
#include <random>
#include <numeric>

// input
#define INIT std::ios::sync_with_stdio(false);std::cin.tie(0);
#define VAR(type, ...)type __VA_ARGS__;MACRO_VAR_Scan(__VA_ARGS__);
template<typename T> void MACRO_VAR_Scan(T& t) { std::cin >> t; }
template<typename First, typename...Rest>void MACRO_VAR_Scan(First& first, Rest&...rest) { std::cin >> first; MACRO_VAR_Scan(rest...); }
#define VEC_ROW(type, n, ...)std::vector<type> __VA_ARGS__;MACRO_VEC_ROW_Init(n, __VA_ARGS__); for(int i=0; i<n; ++i){MACRO_VEC_ROW_Scan(i, __VA_ARGS__);}
template<typename T> void MACRO_VEC_ROW_Init(int n, T& t) { t.resize(n); }
template<typename First, typename...Rest>void MACRO_VEC_ROW_Init(int n, First& first, Rest&...rest) { first.resize(n); MACRO_VEC_ROW_Init(n, rest...); }
template<typename T> void MACRO_VEC_ROW_Scan(int p, T& t) { std::cin >> t[p]; }
template<typename First, typename...Rest>void MACRO_VEC_ROW_Scan(int p, First& first, Rest&...rest) { std::cin >> first[p]; MACRO_VEC_ROW_Scan(p, rest...); }
#define VEC(type, c, n) std::vector<type> c(n);for(auto& i:c)std::cin>>i;
#define MAT(type, c, m, n) std::vector<std::vector<type>> c(m, std::vector<type>(n));for(auto& r:c)for(auto& i:r)std::cin>>i;

// output
#define OUT(d) std::cout<<d;
#define FOUT(n, d) std::cout<<std::fixed<<std::setprecision(n)<<d;
#define SOUT(n, c, d) std::cout<<std::setw(n)<<std::setfill(c)<<d;
#define SP std::cout<<" ";
#define TAB std::cout<<"\t";
#define BR std::cout<<"\n";
#define SPBR(i, n) std::cout<<(i + 1 == n ? '\n' : ' ');
#define ENDL std::cout<<std::endl;
#define FLUSH std::cout<<std::flush;
#define SHOW(d) {std::cerr << #d << "\t:" << d << "\n";}
#define SHOWVECTOR(v) {std::cerr << #v << "\t:";for(const auto& xxx : v){std::cerr << xxx << " ";}std::cerr << "\n";}
#define SHOWVECTOR2(v) {std::cerr << #v << "\t:\n";for(const auto& xxx : v){for(const auto& yyy : xxx){std::cerr << yyy << " ";}std::cerr << "\n";}}
#define SHOWQUEUE(a) {auto tmp(a);std::cerr << #a << "\t:";while(!tmp.empty()){std::cerr << tmp.front() << " ";tmp.pop();}std::cerr << "\n";}

// utility
#define ALL(a) (a).begin(),(a).end()
#define FOR(i, a, b) for(int i=(a);i<(b);++i)
#define RFOR(i, a, b) for(int i=(b)-1;i>=(a);--i)
#define REP(i, n) for(int i=0;i<int(n);++i)
#define RREP(i, n) for(int i=int(n)-1;i>=0;--i)
#define FORLL(i, a, b) for(ll i=ll(a);i<ll(b);++i)
#define RFORLL(i, a, b) for(ll i=ll(b)-1;i>=ll(a);--i)
#define REPLL(i, n) for(ll i=0;i<ll(n);++i)
#define RREPLL(i, n) for(ll i=ll(n)-1;i>=0;--i)
#define IN(a, x, b) (a<=x && x<b)
template<typename T> inline T CHMAX(T& a, const T b) { return a = (a < b) ? b : a; }
template<typename T> inline T CHMIN(T& a, const T b) { return a = (a > b) ? b : a; }
#define EXCEPTION(msg) throw std::string("Exception : " msg " [ in ") + __func__ + " : " + std::to_string(__LINE__) + " lines ]"
#define TRY(cond, msg) try {if (cond) EXCEPTION(msg);}catch (std::string s) {std::cerr << s << std::endl;}
void CHECKTIME(std::function<void()> f) { auto start = std::chrono::system_clock::now(); f(); auto end = std::chrono::system_clock::now(); auto res = std::chrono::duration_cast<std::chrono::nanoseconds>((end - start)).count(); std::cerr << "[Time:" << res << "ns  (" << res / (1.0e9) << "s)]\n"; }

// test
template<class T> std::vector<std::vector<T>> VV(int n) {
	return std::vector<std::vector<T>>(n);
}
template<class T> std::vector<std::vector<T>> VV(int n, int m, T init = T()) {
	return std::vector<std::vector<T>>(n, std::vector<T>(m, init));
}
template<typename S, typename T>
std::ostream& operator<<(std::ostream& os, std::pair<S, T> p) {
	os << "(" << p.first << ", " << p.second << ")"; return os;
}

// type/const

//#define int ll
using ll = long long;
using ull = unsigned long long;
using PAIR = std::pair<int, int>;
using PAIRLL = std::pair<ll, ll>;
constexpr int INFINT = 1 << 30;                          // 1.07x10^ 9
constexpr int INFINT_LIM = (1LL << 31) - 1;              // 2.15x10^ 9
constexpr ll INFLL = 1LL << 60;                          // 1.15x10^18
constexpr ll INFLL_LIM = (1LL << 62) - 1 + (1LL << 62);  // 9.22x10^18
constexpr double EPS = 1e-7;
constexpr int MOD = 1000000007;
constexpr double PI = 3.141592653589793238462643383279;

int n;
int ans;
char a[2100][2100];
std::map<PAIR, std::vector<PAIR>> g;

void erase(PAIR p) {
	for (auto v : g[p]) erase(v);
	g.erase(p);
}

PAIR OK(-1, -1);
PAIR NG(-2, -2);

PAIR dfs(int y1, int x1, int y2, int x2) {
	int cnt = 0;
	FOR(i, y1, y2) FOR(j, x1, x2) {
		cnt += a[i][j] == 'x';
	}
	if (cnt == 0) return OK;

	bool res = true;

	std::vector<int> Y, X;
	FOR(i, y1, y2) {
		if (i % 2 == 0) continue;
		bool f = true;
		FOR(j, x1, x2) {
			if (a[i][j] == 'o') {
				f = false;
				break;
			}
		}
		if (f) Y.emplace_back(i);
	}
	FOR(j, x1, x2) {
		if (j % 2 == 0) continue;
		bool f = true;
		FOR(i, y1, y2) {
			if (a[i][j] == 'o') {
				f = false;
				break;
			}
		}
		if (f) X.emplace_back(j);
	}
	if (Y.empty() && X.empty()) {
		if (cnt > 0) return NG;
		return OK;
	}
	if (Y.empty() || X.empty()) return NG;

	for (auto yi : Y) for (auto xi : X) {
		{
			PAIR p = dfs(y1, x1, yi, xi);
			if (p == NG) {
				continue;
			}
			else if(p != OK) g[PAIR(yi, xi)].emplace_back(p);
		}
		{
			PAIR p = dfs(y1, xi + 1, yi, x2);
			if (p == NG) {
				erase(PAIR(yi, xi));
				continue;
			}
			else if (p != OK) g[PAIR(yi, xi)].emplace_back(p);
		}
		{
			PAIR p = dfs(yi + 1, x1, y2, xi);
			if (p == NG) {
				erase(PAIR(yi, xi));
				continue;
			}
			else if (p != OK) g[PAIR(yi, xi)].emplace_back(p);
		}
		{
			PAIR p = dfs(yi + 1, xi + 1, y2, x2);
			if (p == NG) {
				erase(PAIR(yi, xi));
				continue;
			}
			else if (p != OK) g[PAIR(yi, xi)].emplace_back(p);
		}
		return PAIR(yi, xi);
	}
	return NG;
}

signed main() {
	INIT;
	VAR(int, n);
	REP(i, n) REP(j, n) {
		std::cin >> a[i][j];
	}
	PAIR root = dfs(0, 0, n, n);
	if (root == NG) {
		OUT(-1)BR;
		return 0;
	}
	std::vector<PAIR> ans;
	std::set<PAIR> set;
	set.insert(root);
	while (!set.empty()) {
		PAIR top = *(set.begin());
		set.erase(top);
		for (auto x : g[top]) set.insert(x);
		ans.emplace_back(top);
	}
	OUT(ans.size())BR;
	REP(i, ans.size()) {
		OUT(ans[i].first + 1)BR;
		OUT(ans[i].second + 1)BR;
	}
	return 0;
}
accuracy: 0.5967741935483871
time_ms: 30
memory_kb: 7312
final_rank: 5