Given integers (N, M), a sequence of (N) integers (X = (X_1, X_2, \dots, X_N)), and a sequence of (M) integers (Y = (Y_1, Y_2, \dots, Y_M)). The task is to determine whether there exists an (N \times M) integer matrix (A) with entries between 1 and (N \times M) inclusive such that all entries are distinct, the maximum in row (i) equals (X_i), and the maximum in column (j) equals (Y_j).
Constraints
- (1 \le T \le 10^5)
- (1 \le N, M)
- Sum of (N \times M) over all test cases does not exceed (2 \times 10^5)
- (1 \le X_i, Y_j \le N \times M)
Input
First line contains (T). Each test case follows:
(N\ M) (X_1\ X_2\ \dots\ X_N) (Y_1\ Y_2\ \dots\ Y_M)
Output
For each case, print "No" if impossible. Otherwise print "Yes" followed by the matrix rows.
Core Idea
If (X) or (Y) contains duplicate values, formation is impossible. Excluding that, view the process by iterating values (v) from (N \times M) down to 1.
When placing value (v):
- (v) exists in both (X) and (Y): Set (A_{i,j} = v) for the cell where (X_i = Y_j = v).
- (v) only in (X): For the row with (X_i = v), pick any column (j) where (Y_j > v) and cell is unoccupied.
- (v) only in (Y): For the column with (Y_j = v), pick any row (i) where (X_i > v) and cell is unoccupied.
- (v) absent from both: Pick any unoccupied cell ((i,j)) satisfying (X_i > v) and (Y_j > v).
Because we descend through values, the pool of allowed cells increases monotonically. Thus we can greedily assign cells as long as the required cells exist.
An efficient implemantation groups cells by the minimum of their row/column maximums. For each value (v), a list of cells where (v = \min(X_i, Y_j)) is maintained. Below is a sketch using this grouping approach.
#include <bits/stdc++.h>
using namespace std;
void solve() {
int N, M;
cin >> N >> M;
vector<int> X(N), Y(M);
for (int &x : X) cin >> x;
for (int &y : Y) cin >> y;
unordered_set<int> seenX, seenY;
for (int x : X) if (!seenX.insert(x).second) { cout << "No\n"; return; }
for (int y : Y) if (!seenY.insert(y).second) { cout << "No\n"; return; }
int limit = N * M;
vector<vector<pair<int,int>>> groups(limit + 1);
for (int i = 0; i < N; ++i)
for (int j = 0; j < M; ++j)
groups[min(X[i], Y[j])].emplace_back(i, j);
vector<vector<int>> mat(N, vector<int>(M));
vector<int> rowAssigned(N, 0), colAssigned(M, 0);
int rowCount = 0, colCount = 0;
int nextFree = 1;
for (int v = limit; v >= 1; --v) {
for (auto [r, c] : groups[v]) {
if (!rowAssigned[r] && !colAssigned[c]) {
mat[r][c] = v;
rowAssigned[r] = colAssigned[c] = 1;
rowCount++, colCount++;
}
}
}
for (int i = 0; i < N; ++i) if (!rowAssigned[i]) { cout << "No\n"; return; }
for (int j = 0; j < M; ++j) if (!colAssigned[j]) { cout << "No\n"; return; }
cout << "Yes\n";
for (int i = 0; i < N; ++i)
for (int j = 0; j < M; ++j)
cout << mat[i][j] << " \n"[j == M-1];
}
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int T; cin >> T;
while (T--) solve();
return 0;
}
The solution guarantees correctness by only placing numbers into cells scheduled by the minimum of their row/column constraints, verifying that each row and column receives exactly one designated maximum, and allowing smaller values to fill remaining free cells.