1. Abridged Problem Statement  
Given an N×N chessboard (1≤N≤40) with P removed cells, determine if the remaining cells can be fully covered by non-overlapping 2×1 dominoes placed on adjacent squares. If a tiling exists, output “Yes,” then list all horizontal dominoes by the coordinates of their left cell, and all vertical dominoes by the coordinates of their bottom cell; otherwise, output “No.”

2. Detailed Editorial  
   Problem → Domino tiling on a grid with holes.  
   Key fact: on a checkerboard coloring, any valid domino covers exactly one black and one white cell. A perfect tiling of all free cells thus corresponds one-to-one to a perfect matching in the bipartite graph whose vertices are free black and white cells and whose edges connect orthogonally adjacent free cells.

   Steps:  
   1. Read N, P and mark removed cells on an N×N boolean board.  
   2. Count free cells; if odd, immediately print “No.”  
   3. Partition free cells by color (parity of i+j). Number black cells from 0…B−1, white from 0…W−1.  
   4. Build a bipartite graph: for each black cell, add an edge to each free white neighbor (up/down/left/right).  
   5. Run Hopcroft–Karp to find maximum matching in O(E√V).  
   6. If matched-edge count ×2 ≠ total free cells, tiling is impossible → “No.”  
   7. Otherwise extract each matched black–white pair as one domino, classify it as horizontal or vertical, normalize to its left or bottom square, and output counts and coordinates.

   Complexity:  
   - V=O(N²)≤1600, E=O(4V), Hopcroft–Karp runs in O(E√V)≈O(N²·N)=O(N³) worst case, easily within time for N≤40.

3. Provided C++ Solution with Detailed Comments  
```cpp
#include <bits/stdc++.h>
using namespace std;

// Convenience overloads for I/O of pairs and vectors
template<typename T1, typename T2>
ostream& operator<<(ostream& out, const pair<T1, T2>& x) {
    return out << x.first << ' ' << x.second;
}
template<typename T1, typename T2>
istream& operator>>(istream& in, pair<T1, T2>& x) {
    return in >> x.first >> x.second;
}
template<typename T>
istream& operator>>(istream& in, vector<T>& a) {
    for(auto& x: a) in >> x;
    return in;
}
template<typename T>
ostream& operator<<(ostream& out, const vector<T>& a) {
    for(auto& x: a) out << x << ' ';
    return out;
}

// Hopcroft–Karp for bipartite matching in O(E sqrt(V))
class HopcroftKarp {
  private:
    int n, m;                  // sizes of left and right partitions
    vector<vector<int>> adj;   // adjacency list from left to right
    vector<int> dist;          // distances used in BFS
    
    // BFS builds layers, returns true if there is an augmenting path
    bool bfs() {
        queue<int> q;
        dist.assign(n, -1);
        // Start from all free (unmatched) left vertices
        for(int u = 0; u < n; u++) {
            if(inv_match[u] == -1) {
                dist[u] = 0;
                q.push(u);
            }
        }
        bool found = false;
        while(!q.empty()) {
            int u = q.front(); q.pop();
            for(int v: adj[u]) {
                int mu = match[v];
                if(mu == -1) {
                    // can reach a free right node ⇒ augmenting path exists
                    found = true;
                } else if(dist[mu] == -1) {
                    // visit the paired left node next
                    dist[mu] = dist[u] + 1;
                    q.push(mu);
                }
            }
        }
        return found;
    }
    
    // DFS tries to grow an augmenting path from left node u
    bool dfs(int u) {
        for(int v: adj[u]) {
            int mu = match[v];
            if(mu == -1 || (dist[mu] == dist[u] + 1 && dfs(mu))) {
                // match u<->v
                inv_match[u] = v;
                match[v] = u;
                return true;
            }
        }
        dist[u] = -1; // dead end, prune
        return false;
    }

  public:
    vector<int> match, inv_match;   // match[y]=x, inv_match[x]=y or -1
    HopcroftKarp(int _n, int _m) : n(_n), m(_m) {
        adj.assign(n, {});
        match.assign(m, -1);
        inv_match.assign(n, -1);
    }
    
    // Add an edge from left node u to right node v
    void add_edge(int u, int v) { adj[u].push_back(v); }
    
    // Compute maximum matching
    int max_matching() {
        int flow = 0;
        while(bfs()) {
            for(int u = 0; u < n; u++) {
                if(inv_match[u] == -1 && dfs(u))
                    flow++;
            }
        }
        return flow;
    }
    
    // Retrieve the matched pairs as (left_index, right_index)
    vector<pair<int,int>> get_matching() {
        vector<pair<int,int>> result;
        for(int u = 0; u < n; u++) {
            if(inv_match[u] != -1)
                result.emplace_back(u, inv_match[u]);
        }
        return result;
    }
};

int n, p;
vector<pair<int,int>> removed;

// Read board size and removed cells
void read_input() {
    cin >> n >> p;
    removed.resize(p);
    cin >> removed;
}

void solve() {
    // Build board, true=free
    vector<vector<bool>> board(n+1, vector<bool>(n+1, true));
    int free_cells = n*n;
    for(auto &rc : removed) {
        board[rc.first][rc.second] = false;
        free_cells--;
    }
    // Odd number of free cells ⇒ impossible
    if(free_cells % 2) {
        cout << "No\n";
        return;
    }
    // Partition free cells by checker parity
    vector<pair<int,int>> black_cells, white_cells;
    map<pair<int,int>,int> bid, wid;
    for(int i = 1; i <= n; i++) {
        for(int j = 1; j <= n; j++) {
            if(!board[i][j]) continue;
            if(((i + j) & 1) == 0) {
                bid[{i,j}] = black_cells.size();
                black_cells.emplace_back(i,j);
            } else {
                wid[{i,j}] = white_cells.size();
                white_cells.emplace_back(i,j);
            }
        }
    }
    // Build bipartite graph
    HopcroftKarp hk(black_cells.size(), white_cells.size());
    int dx[4] = {-1,1,0,0}, dy[4] = {0,0,-1,1};
    for(int i = 0; i < (int)black_cells.size(); i++) {
        auto [x,y] = black_cells[i];
        for(int d=0; d<4; d++){
            int nx=x+dx[d], ny=y+dy[d];
            if(nx>=1&&nx<=n&&ny>=1&&ny<=n && board[nx][ny]) {
                auto it = wid.find({nx,ny});
                if(it!=wid.end()) hk.add_edge(i, it->second);
            }
        }
    }
    // Find maximum matching
    int match_sz = hk.max_matching();
    if(match_sz*2 != free_cells) {
        cout << "No\n";
        return;
    }
    // We have a perfect tiling
    cout << "Yes\n";
    vector<pair<int,int>> H, V;
    // Extract each matched domino
    for(int i=0; i< (int)black_cells.size(); i++){
        int w = hk.inv_match[i];
        if(w == -1) continue;
        auto [bx,by] = black_cells[i];
        auto [wx,wy] = white_cells[w];
        if(bx == wx) {
            // horizontal domino, normalize to left coordinate
            if(by < wy) H.emplace_back(bx,by);
            else       H.emplace_back(wx,wy);
        } else {
            // vertical domino, normalize to bottom coordinate
            if(bx < wx) V.emplace_back(bx,by);
            else        V.emplace_back(wx,wy);
        }
    }
    // Output vertical then horizontal as per statement
    cout << V.size() << "\n";
    for(auto &c: V) cout << c.first << " " << c.second << "\n";
    cout << H.size() << "\n";
    for(auto &c: H) cout << c.first << " " << c.second << "\n";
}

int main(){
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    read_input();
    solve();
    return 0;
}
```

4. Python Solution with Detailed Comments  
```python
import sys
from collections import deque

def hopcroft_karp(adj, n_left, n_right):
    # adj: list of lists, adj[u] = neighbors v in [0..n_right)
    INF = 10**9
    pair_u = [-1]*n_left
    pair_v = [-1]*n_right
    dist = [0]*n_left

    def bfs():
        queue = deque()
        for u in range(n_left):
            if pair_u[u] == -1:
                dist[u] = 0
                queue.append(u)
            else:
                dist[u] = INF
        found_augment = False
        while queue:
            u = queue.popleft()
            for v in adj[u]:
                pu = pair_v[v]
                if pu == -1:
                    found_augment = True
                elif dist[pu] == INF:
                    dist[pu] = dist[u] + 1
                    queue.append(pu)
        return found_augment

    def dfs(u):
        for v in adj[u]:
            pu = pair_v[v]
            if pu == -1 or (dist[pu] == dist[u] + 1 and dfs(pu)):
                pair_u[u] = v
                pair_v[v] = u
                return True
        dist[u] = INF
        return False

    matching = 0
    while bfs():
        for u in range(n_left):
            if pair_u[u] == -1 and dfs(u):
                matching += 1
    return matching, pair_u, pair_v

def main():
    input_data = sys.stdin.read().strip().split()
    it = iter(input_data)
    n, p = map(int, (next(it), next(it)))
    removed = set()
    for _ in range(p):
        x, y = map(int, (next(it), next(it)))
        removed.add((x,y))

    # Build board of free cells
    total = n*n - p
    # If odd free cells, impossible
    if total % 2:
        print("No")
        return

    black, white = [], []
    bid, wid = {}, {}
    for i in range(1, n+1):
        for j in range(1, n+1):
            if (i,j) in removed: continue
            if (i+j) & 1 == 0:
                bid[(i,j)] = len(black)
                black.append((i,j))
            else:
                wid[(i,j)] = len(white)
                white.append((i,j))

    # Build adjacency from blacks to whites
    adj = [[] for _ in range(len(black))]
    dirs = [(-1,0),(1,0),(0,-1),(0,1)]
    for u,(x,y) in enumerate(black):
        for dx,dy in dirs:
            vcoord = (x+dx, y+dy)
            if vcoord in wid:
                adj[u].append(wid[vcoord])

    # Run matching
    match_sz, pair_u, pair_v = hopcroft_karp(adj, len(black), len(white))
    if match_sz*2 != total:
        print("No")
        return

    print("Yes")
    horiz, vert = [], []
    # Each u matched to pair_u[u] ⇒ a domino
    for u,v in enumerate(pair_u):
        if v == -1: continue
        bx, by = black[u]
        wx, wy = white[v]
        if bx == wx:
            # horizontal: choose left cell
            if by < wy: horiz.append((bx,by))
            else:       horiz.append((wx,wy))
        else:
            # vertical: choose bottom cell
            if bx < wx: vert.append((bx,by))
            else:       vert.append((wx,wy))

    # Output vertical then horizontal (vertical count first)
    print(len(vert))
    for x,y in vert: print(x, y)
    print(len(horiz))
    for x,y in horiz: print(x, y)

if __name__ == "__main__":
    main()
```

5. Compressed Editorial  
Color free cells checkerboard‐style, build a bipartite graph between black and white free cells with edges for orthogonal adjacency, and check for a perfect matching via Hopcroft–Karp. If the matching covers all free cells, output the matched pairs as domino placements; otherwise print “No.”