#include #include #include #include #include #include using namespace std; typedef long long ll; void transpose(vector& v) { int r = (int)v.size(); int c = (int)v[0].size(); if(c < r) return; vector nv; nv.reserve(c); for(int i = 0; i < c; i++) nv.push_back(""); for(int i = 0; i < r; i++) for(int j = 0; j < c; j++) nv[j] += v[i][j]; v.swap(nv); assert(v[0].size() <= v.size()); } const int NUM_BITS = 4; const int LOW_ORDER = (1 << NUM_BITS) - 1; void mergeWindow(int& x, int y, ll& state, int numCols) { if(x == y) return; assert(x != y); assert(x > 0 && y > 0); if(x > y) swap(x, y); if(x == 2 && y == 3) { x = 1; ll nstate = 0; for(int i = 0; i < numCols; i++) { int curr = (state >> (i * NUM_BITS)) & LOW_ORDER; if(curr == 2 || curr == 3) nstate |= (1LL << (i * NUM_BITS)); else nstate |= (((ll)curr) << (i * NUM_BITS)); } state = nstate; } else { ll nstate = 0; for(int i = 0; i < numCols; i++) { int curr = (state >> (i * NUM_BITS)) & LOW_ORDER; if(curr == y) nstate |= (((ll)x) << (i * NUM_BITS)); else nstate |= (((ll)curr) << (i * NUM_BITS)); } state = nstate; } } int srctodst[LOW_ORDER+1]; void normalize(ll& key, int numSquares) { memset(srctodst, -1, sizeof(srctodst)); srctodst[0] = 0; srctodst[1] = 1; srctodst[2] = 2; srctodst[3] = 3; int nxtidx = 4; ll nkey = 0; for(int i = 0; i < numSquares; i++) { int comp = (key >> (NUM_BITS * i)) & LOW_ORDER; if(comp == 0) continue; assert(comp <= LOW_ORDER); if(srctodst[comp] == -1) srctodst[comp] = nxtidx++; nkey |= ((ll)srctodst[comp]) << (NUM_BITS * i); } key = nkey; } vector g; unordered_map ndp; void pillar(ll state, int currAmt, int currrow, int currcol, int numCols) { assert(g[currrow][currcol] == '#'); { int topItem = (state >> (NUM_BITS * (numCols-1))); if(topItem > 1) { bool present = false; for(int i = 0; i < numCols-1 && !present; i++) { int otherItem = (state >> (NUM_BITS * i)) & LOW_ORDER; present = topItem == otherItem; } if(!present) return; } } ll nstate = state; nstate <<= NUM_BITS; nstate &= (1LL << ((numCols) * NUM_BITS)) - 1; normalize(nstate, numCols); ndp[nstate] = max(ndp[nstate], currAmt); } void addstore(ll state, int currAmt, int currrow, int currcol, int numCols) { assert(g[currrow][currcol] == '.'); { int topItem = (state >> (NUM_BITS * (numCols-1))); if(topItem > 1) { bool present = false; for(int i = 0; i < numCols-1 && !present; i++) { int otherItem = (state >> (NUM_BITS * i)) & LOW_ORDER; present = topItem == otherItem; } if(!present) return; } } if(currrow > 0) { int lhs = ((state >> (NUM_BITS * (numCols-1)))) & LOW_ORDER; if(lhs > 0 && g[currrow-1][currcol] == '.') currAmt++; } if(currcol > 0) { int lhs = state & LOW_ORDER; if(lhs > 0 && g[currrow][currcol-1] == '.') currAmt++; } ll nstate = state; nstate <<= NUM_BITS; nstate &= (1LL << ((numCols) * NUM_BITS)) - 1; normalize(nstate, numCols); ndp[nstate] = max(ndp[nstate], currAmt); } void keepempty(ll state, int currAmt, int currrow, int currcol, int numCols) { assert(g[currrow][currcol] != '#'); ll nstate = state; int nidx = LOW_ORDER; if(g[currrow][currcol] == 'U' || g[currrow][currcol] == 'D') { if(g[currrow][currcol] == 'U') nidx = 2; else nidx = 3; } else { if(currrow > 0) { int lhs = ((state >> (NUM_BITS * (numCols-1)))) & LOW_ORDER; if(lhs == 0 && g[currrow-1][currcol] == '.') currAmt++; } if(currcol > 0) { int lhs = state & LOW_ORDER; if(lhs == 0 && g[currrow][currcol-1] == '.') currAmt++; } } if(currrow > 0) { int lhs = ((state >> (NUM_BITS * (numCols-1)))) & LOW_ORDER; if(lhs > 0) mergeWindow(nidx, lhs, nstate, numCols); } if(currcol > 0) { int lhs = state & LOW_ORDER; if(lhs > 0) mergeWindow(nidx, lhs, nstate, numCols); } nstate <<= NUM_BITS; nstate |= nidx; nstate &= (1LL << (numCols * NUM_BITS)) - 1; normalize(nstate, numCols); ndp[nstate] = max(ndp[nstate], currAmt); } unordered_map dp; int ret; int main() { { int r, c; cin >> r >> c; g.resize(r); for(int i = 0; i < r; i++) cin >> g[i]; transpose(g); } int numCols = (int)g[0].size(); { dp[0] = 0; } int highestS = 0; for(int i = 0; i < (int)g.size(); i++) { for(int j = 0; j < (int)g[i].size(); j++) { ndp.clear(); for(auto& state: dp) { if(g[i][j] == '#') { pillar(state.first, state.second, i, j, numCols); } if(g[i][j] == '.') { addstore(state.first, state.second, i, j, numCols); } if(g[i][j] != '#') { keepempty(state.first, state.second, i, j, numCols); } } dp.swap(ndp); for(auto& state: dp) { bool allOne = true; if(state.second <= ret) continue; for(int i = 0; i < numCols; i++) { int curr = (state.first >> (NUM_BITS * i)) & LOW_ORDER; if(curr == 0) continue; highestS = max(highestS, curr); allOne &= curr == 1; } if(allOne) ret = state.second; } } } cout << ret << "\n"; }