#include <iostream>
#include <vector>
#include <string>
#include <algorithm>
#include <set>
using namespace std;
struct Point {
int r, c;
bool operator<(const Point& o) const {
return r != o.r ? r < o.r : c < o.c;
}
};
class PuzzleSolver {
int N, M;
vector<vector<vector<string>>> pieces; // FIXED: Changed to 3D vector
vector<vector<int>> board;
int totalTiles = 0;
// Normalize piece to top-left corner
vector<string> normalize(vector<string> piece) {
int minR = N, minC = N, maxR = -1, maxC = -1;
for (int i = 0; i < piece.size(); i++) {
for (int j = 0; j < piece[i].size(); j++) {
if (piece[i][j] == '#') {
minR = min(minR, i);
maxR = max(maxR, i);
minC = min(minC, j);
maxC = max(maxC, j);
}
}
}
vector<string> result(maxR - minR + 1, string(maxC - minC + 1, '.'));
for (int i = minR; i <= maxR; i++) {
for (int j = minC; j <= maxC; j++) {
if (piece[i][j] == '#') {
result[i - minR][j - minC] = '#';
}
}
}
return result;
}
// Rotate piece 90 degrees clockwise
vector<string> rotate(const vector<string>& piece) {
int h = piece.size();
int w = piece[0].size();
vector<string> rotated(w, string(h, '.'));
for (int i = 0; i < h; i++) {
for (int j = 0; j < w; j++) {
rotated[j][h - 1 - i] = piece[i][j];
}
}
return normalize(rotated);
}
// Generate all unique rotations
vector<vector<string>> getRotations(vector<string> piece) {
set<vector<string>> unique;
vector<string> current = normalize(piece);
for (int i = 0; i < 4; i++) {
unique.insert(current);
current = rotate(current);
}
return vector<vector<string>>(unique.begin(), unique.end());
}
// Check if piece can be placed at position (r, c)
bool canPlace(const vector<string>& piece, int r, int c) {
int h = piece.size();
int w = piece[0].size();
if (r + h > N || c + w > N) return false;
for (int i = 0; i < h; i++) {
for (int j = 0; j < w; j++) {
if (piece[i][j] == '#' && board[r + i][c + j] != 0) {
return false;
}
}
}
return true;
}
// Place piece on board
void place(const vector<string>& piece, int r, int c, int pieceId) {
int h = piece.size();
int w = piece[0].size();
for (int i = 0; i < h; i++) {
for (int j = 0; j < w; j++) {
if (piece[i][j] == '#') {
board[r + i][c + j] = pieceId;
}
}
}
}
// Remove piece from board
void remove(const vector<string>& piece, int r, int c) {
int h = piece.size();
int w = piece[0].size();
for (int i = 0; i < h; i++) {
for (int j = 0; j < w; j++) {
if (piece[i][j] == '#') {
board[r + i][c + j] = 0;
}
}
}
}
// Count tiles in piece
int countTiles(const vector<string>& piece) {
int count = 0;
for (const auto& row : piece) {
for (char c : row) {
if (c == '#') count++;
}
}
return count;
}
// Backtracking solver
bool solve(int pieceIdx) {
if (pieceIdx == M) {
// Check if all cells are filled
for (int i = 0; i < N; i++) {
for (int j = 0; j < N; j++) {
if (board[i][j] == 0) return false;
}
}
return true;
}
// Try all rotations of current piece
for (const auto& rotation : pieces[pieceIdx]) {
// Try all positions
for (int r = 0; r < N; r++) {
for (int c = 0; c < N; c++) {
if (canPlace(rotation, r, c)) {
place(rotation, r, c, pieceIdx + 1);
if (solve(pieceIdx + 1)) {
return true;
}
remove(rotation, r, c);
}
}
}
}
return false;
}
public:
bool solvePuzzle(int n, int m, vector<vector<string>>& inputPieces) {
N = n;
M = m;
board.assign(N, vector<int>(N, 0));
pieces.clear();
totalTiles = 0;
// Preprocess pieces: generate all rotations
for (auto& piece : inputPieces) {
vector<string> normalized = normalize(piece);
totalTiles += countTiles(normalized);
pieces.push_back(getRotations(normalized));
}
// Early exit: check if total tiles match board size
if (totalTiles != N * N) {
return false;
}
return solve(0);
}
};
int main() {
ios_base::sync_with_stdio(false);
cin.tie(NULL);
int N, M;
cin >> N >> M;
cin.ignore();
vector<vector<string>> pieces(M);
for (int i = 0; i < M; i++) {
vector<string> piece(N);
for (int j = 0; j < N; j++) {
getline(cin, piece[j]);
}
pieces[i] = piece;
}
PuzzleSolver solver;
if (solver.solvePuzzle(N, M, pieces)) {
cout << "yes" << endl;
} else {
cout << "no" << endl;
}
return 0;
}