Editorial for Cắt bảng
Remember to use this editorial only when stuck, and not to copy-paste code from it. Please be respectful to the problem author and editorialist.
Submitting an official solution before solving the problem yourself is a bannable offence.
Submitting an official solution before solving the problem yourself is a bannable offence.
Author:
Trong lời giải này, các cột và các dòng được đánh số từ ~0~.
Nhận xét rằng:
- Phép cắt dọc giữa cột ~y~ và ~y+1~ thật chất là phép xoay theo vòng tròn các cột của bảng về bên phải ~y~ ô (ta xem cột ~m~ nằm bên trái cột ~1~). Nói cách khác, ô ~(i, j)~ sẽ trở thành ô ~(i, (j+y) \bmod m)~.
- Phép cắt ngang giữa dòng ~x~ và ~x+1~ thật chất là phép xoay theo vòng tròn các dòng của bảng về bên dưới ~y~ ô (ta xem dòng ~n~ nằm bên trên cột ~1~). Nói cách khác, ô ~(i, j)~ sẽ trở thành ô ~((i+x) \bmod n, j)~.
Với nhận xét trên, từ bảng ~a~ ban đầu, bản nhận được chỉ có thể là bảng $a$ sau khi xoay theo vòng tròn về bên phải ~d_y~ ô và xoay theo vòng tròn về bên dưới ~d_x~ ô (với ~0 \le d_x < n~, ~0 \le d_y < m~). Do đó, ta cần kiểm tra xem có tồn tại cặp giá trị ~(d_x, d_y)~ nào mà sau khi xoay thì bảng ~a~ trở thành bảng ~b~ hay không.
Độ phức tạp: ~O(n^2 \times m^2)~.
#include <bits/stdc++.h> using namespace std; typedef pair<int, int> pii; void solve() { int n, m; cin >> n >> m; vector<vector<int>> a(n, vector<int>(m, 0)); for(int i = 0; i < n; ++i) { for(int j = 0; j < m; ++j) { cin >> a[i][j]; } } vector<vector<int>> b(n, vector<int>(m, 0)); for(int i = 0; i < n; ++i) { for(int j = 0; j < m; ++j) { cin >> b[i][j]; } } for(int dx = 0; dx < n; ++dx) { for(int dy = 0; dy < m; ++dy) { bool ok = true; for(int i = 0; i < n; ++i) { for(int j = 0; j < m; ++j) { if (a[i][j] != b[(i+dx)%n][(j+dy)%m]) { ok = false; } } } if (ok) { puts("YES"); return; } } } puts("NO"); } int main() { int t; cin >> t; while (t--) solve(); return 0; }
Comments