#include using namespace std; //#define int long long typedef vector vi; typedef vector vvi; typedef pair ii; typedef vector vii; typedef vector vvii; void dfs_components(vvi& adj, vi& compNum, vi& comp, int cn, int v) { if (compNum[v] != -1) return; compNum[v] = cn; comp.push_back(v); for (int u : adj[v]) { dfs_components(adj, compNum, comp, cn, u); } } void dfsBridges(int v, int p, int& timer, vvi& adj, vi& used, vi& tin, vi& fup, vii& bridges) { used[v] = 1; tin[v] = fup[v] = timer++; for (int u : adj[v]) { if (u == p) continue; if (!used[u]) { dfsBridges(u, v, timer, adj, used, tin, fup, bridges); fup[v] = min(fup[v], fup[u]); if (tin[v] < fup[u]) bridges.emplace_back(v, u); } else fup[v] = min(fup[v], tin[u]); } } void findBridges(vvi& adj, vii& bridges) { int n = (int)adj.size()-1; vi used(n+1); vi tin(n+1), fup(n+1); int timer = 0; for (int i=1; i <= n; ++i) { if (!used[i]) { dfsBridges(i, -1, timer, adj, used, tin, fup, bridges); } } } int r_n, r_m; vii pairify(vi v) { vii ans; for (int i=0; i < (int)v.size(); ++i) { ans.emplace_back(v[i]/r_m, v[i]%r_m); } return ans; } vii rectify (vii v) { int minx = 1e9; int miny = 1e9; for (int i=0; i < (int)v.size(); ++i) { minx = min(v[i].first, minx); miny = min(v[i].second, miny); } for (int i=0; i < (int)v.size(); ++i) { v[i] = make_pair(v[i].first-minx, v[i].second-miny); } sort(v.begin(), v.end()); return v; } vii rrotate(vii v) { for (int i=0; i < (int)v.size(); ++i) { v[i] = ii(-v[i].second, v[i].first); } return rectify(v); } signed main() { ios_base::sync_with_stdio(0); int n, m; cin >> n >> m; r_n = n; r_m = m; int nv = 0; vector parch(n); vvi g(n*m); for (int i=0; i < n; ++i) { cin >> parch[i]; for (int j=0; j < m; ++j) { if(parch[i][j] == '#') nv++; } } auto idx = [&] (int x, int y) { return m*x + y; }; auto add_edge = [&] (int x1, int y1, int x2, int y2) { if (x1 < 0 || x1 >= n || x2 < 0 || x2 >= n || y1 < 0 || y1 >= m || y2 < 0 || y2 >= m) return; if (parch[x1][y1] == '#' && parch[x2][y2] == '#') { g[idx(x1, y1)].push_back(idx(x2, y2)); g[idx(x2, y2)].push_back(idx(x1, y1)); } }; for (int i=0; i < n; ++i) { for (int j=0; j < m; ++j) { add_edge(i, j, i+1, j); add_edge(i, j, i, j+1); } } vii bridges; findBridges(g, bridges); set bset; for (ii x : bridges) { bset.insert(x); bset.emplace(x.second, x.first); } vvi g2(n*m); for (int u = 0; u < n*m; ++u) { for (int v : g[u]) { if (bset.find(ii(u, v)) == bset.end()) { g2[u].push_back(v); } } } vi compNum = vi(n*m, -1); vvi comps; int ccn = 0; for (int i = 0; i < n; ++i) { for (int j = 0; j < m; ++j) { if (compNum[idx(i, j)] && parch[i][j] == '#') { vi ccomp; dfs_components(g2, compNum, ccomp, ccn++, idx(i, j)); comps.push_back(ccomp); } } } int NC = comps.size(); vvi tree_adj(NC); for (ii x : bridges) { int u = compNum[x.first]; int v = compNum[x.second]; tree_adj[u].push_back(v); tree_adj[v].push_back(u); } for (int i=1; i <= nv; ++i) { if (nv % i == 0) { vi marked(NC); function add_comp = [&] (int u, int p, vi& c) { marked[u] = 1; c.push_back(u); for (int v : tree_adj[u]) { if (v == p) continue; if (marked[v]) continue; add_comp(v, u, c); } }; vvi lcc; function dfs_greedy = [&] (int u, int p) -> int { int siz = comps[u].size(); for (int v : tree_adj[u]) { if (v == p) continue; int ret = dfs_greedy(v, u); if (ret == -1) return -1; siz += ret; } if (siz == i) { vi cc; add_comp(u, p, cc); lcc.push_back(cc); return 0; } else if (siz > i) return -1; return siz; }; int ret0 = dfs_greedy(0, -1); if (ret0 != 0) continue; // vi cc0; // add_comp(0, -1, cc0);/ // lcc.push_back(cc0); vvii good_ones; function expand = [&] (vi v) { vi ans; for (int i : v) { for (int x : comps[i]) ans.push_back(x); } return ans; }; good_ones.push_back(rectify(pairify(expand(lcc[0])))); good_ones.push_back(rrotate(good_ones.back())); good_ones.push_back(rrotate(good_ones.back())); good_ones.push_back(rrotate(good_ones.back())); bool good = true; for (int j=1; j < nv/i; ++j) { bool cg = false; vii curr = rectify(pairify(expand(lcc[j]))); for (int k=0; k < (int)good_ones.size(); ++k) { if (curr == good_ones[k]) cg = true; } if (!cg) good = false; } if (good) { cout << nv/i << endl; return 0; } } } }