Problem:
問題文
落書きの魔女 ALBERTINE は
W
列
H
行の正方形のセルからなる長方形の結界の入り口に落書きをしている．この世界では落書きは必ずセルを白色か黒色で塗ることによって成り立つ．
すでに使い魔 ANJA の手によって落書きの一部が描かれているのだが，落書きの魔女は残りすべてのセルを塗り落書きを完成させたい．落書きの魔女にはあるこだわりがある．そのこだわりとは次のようなものである．
2
つの異なるセルが辺を共有するとき，
2
つのセルは隣接していると呼ぶことにする．完成された落書きにおいては，任意の
2
つの黒いセルについて，片方からもう片方への隣接した黒いセルをたどるパスがちょうど
1
つだけ存在していなければならない．
どの
2
つの白色のセルも隣接してはならない．
また，落書きの魔女は黒色が好きなので，こだわりを満たした状態でなおかつ最も黒色のセルが多い落書きを完成させたい．果たして落書きの魔女は最大で何個のセルが黒色に塗られたこだわりの落書きを描くことができるだろうか．
入力形式
入力は以下の形式で与えられる．
H\ W\\
c_{11} c_{12} ... c_{1W}\\
c_{21} c_{22} ... c_{2W}\\
...\\
c_{H1} c_{H2} ... c_{HW}\\
H
は結界の入り口の縦幅，
W
は結界の入り口の横幅を表す．
c_{ij}
は各セルの状態を表す文字であり，上から
i
行目，左から
j
列目のセルの状態を表す．セルに黒色が塗られている場合は
c_{ij}
は
'#'
となり，白色が塗られている場合は
'.'
，まだ色が塗られていない場合はそうでない場合は
'?'
となる．
出力形式
魔女のこだわりを満たした状態でとりうる黒色のセルの個数の最大値を
1
行で出力せよ．
もしどのように塗っても魔女のこだわりを満たすように出来ない場合，
-1
と出力せよ．
制約
1 ≤ H ≤ 11
1 ≤ W ≤ 11
c_{ij}
は
'#'
,
'.'
,
'?'
のいずれかである．
入出力例
入力例 1
3 4
.##.
#??#
.#?#
出力例1
8
入力例 2
5 5
##?##
#???#
?????
#???#
##?##
出力例 2
19
入力例 3
9 2
##
..
??
??
??
??
??
??
??
出力例 3
-1
入力例 4
7 9
??#####??
?#?????#?
?#?????#?
?#??#??#?
?#???#?#?
??#####??
???????#?
出力例 4
44
入力例 5
11 11
???????????
???####????
???#???#???
???#???#???
???#???#???
???####????
???#???#???
???#???#???
???#???#???
???####????
???????????
出力例 5
86
Problem Setter: Flat35

Submitted solutions:

code_snippet: // AOJ #2314 Scribbling witch
// 2025.5.30

#include <bits/stdc++.h>
using namespace std;
using ll = long long;
const int MAX = 11;

int h, w;
char B[MAX][MAX+1];
map<ll,int> memo[MAX][MAX];
char mapto[16];
int nxt(ll, int, int, char);

inline int Get(ll s, int i) {
    int v = (s >> (i*4)) & 0xF;
    return (v<<28)>>28;
}
inline void Set(ll &s, int v, int i) {
    s &= ~((ll)0xF << (i*4));
    s |= (ll)(v&0xF) << (i*4);
}

int calc(ll st, int x, int y) {
    if (x==w) return calc(st, 0, y+1);
    if (y==h) {
        for(int i=0;i<w;i++) if (Get(st,i)>0) return -1;
        return 0;
    }
    auto &mp = memo[y][x];
    if (mp.count(st)) return mp[st];

    int ans = -1;
    char c0 = B[y][x];
    if (c0=='#' || c0=='?') ans = max(ans, nxt(st, x, y, '#'));
    if (c0=='.' || c0=='?') ans = max(ans, nxt(st, x, y, '.'));
    return mp[st] = ans;
}


int nxt(ll st, int x, int y, char c) {
    int pc = Get(st,x);
    int lc = x>0 ? Get(st,x-1) : -1;
    int add = 0;
    if (c=='#') {
        add = 1;
        if (lc>=0 && lc==pc) return -1;
        if (lc>=0) {
            Set(st, lc, x);
            if (pc>=0) {
                for(int i=0;i<w;i++) if (Get(st,i)==pc) Set(st, lc, i);
            }
        } else if (pc==-1) Set(st, 7, x);
        else Set(st, pc, x);
    } else {
        if ((y>0 && pc==-1) || (x>0 && lc==-1)) return -1;
        Set(st, -1, x);
        if (pc!=-1) {
            bool ok=false;
            for(int i=0;i<w;i++) if (Get(st,i)==pc){ ok=true; break; }
            if (!ok) return -1;
        }
    }
    memset(mapto, -1, sizeof(mapto));
    int mcnt=0;
    for(int i=0;i<w;i++){
        int v = Get(st,i);
        if (v!=-1) {
            if (mapto[v]==-1) mapto[v]=mcnt++;
            Set(st, mapto[v], i);
        }
    }
    int sub = calc(st, x+1, y);
    return sub<0 ? -1 : sub+add;
}

int main(){
    ios::sync_with_stdio(0);
    cin.tie(0);

    cin >> h >> w;
    for(int y=0;y<h;y++) cin >> B[y];
    if (w==1) {
        if (h==1) {
            cout << (B[0][0]=='.' ? 0 : 1) << endl;
            return 0;
        }
        int ans = -1;
        for(int L=0;L<=1;L++){
            for(int R=max(L,h-2); R<=h-1; R++){
                if (L>R) continue;
                bool ok = true;
                for(int i=L;i<=R;i++){
                    if (B[i][0]=='.') ok=false;
                }
                for(int i=0;i<L;i++){
                    if (B[i][0]=='#') ok=false;
                }
                for(int i=R+1;i<h;i++){
                    if (B[i][0]=='#') ok=false;
                }
                if (!ok) continue;
                ans = max(ans, R-L+1);
            }
        }
        cout << ans << endl;
        return 0;
    }
    for(int y=0;y<h;y++){
        for(int x=0;x<w;x++){
            memo[y][x].clear();
        }
    }
    int ans = calc(-1LL, 0, 0);
    cout << ans << endl;
    return 0;
}
accuracy: 1
time_ms: 90
memory_kb: 21376
final_rank: 5

code_snippet: // AOJ #2314 Scribbling witch
// 2025.5.30

#include <bits/stdc++.h>
using namespace std;
using ll = long long;
const int MAX = 11;

int h, w;
char B[MAX][MAX+1];
map<ll,int> memo[MAX][MAX];
char mapto[16];
int nxt(ll, int, int, char);

inline int Get(ll s, int i) {
    int v = (s >> (i*4)) & 0xF;
    return (v<<28)>>28;
}
inline void Set(ll &s, int v, int i) {
    s &= ~((ll)0xF << (i*4));
    s |= (ll)(v&0xF) << (i*4);
}

int calc(ll st, int x, int y) {
    if (x==w) return calc(st, 0, y+1);
    if (y==h) {
        for(int i=0;i<w;i++) if (Get(st,i)>0) return -1;
        return 0;
    }
    auto &mp = memo[y][x];
    if (mp.count(st)) return mp[st];

    int ans = -1;
    char c0 = B[y][x];
    if (c0=='#' || c0=='?') ans = max(ans, nxt(st, x, y, '#'));
    if (c0=='.' || c0=='?') ans = max(ans, nxt(st, x, y, '.'));
    return mp[st] = ans;
}


int nxt(ll st, int x, int y, char c) {
    int pc = Get(st,x);
    int lc = x>0 ? Get(st,x-1) : -1;
    int add = 0;
    if (c=='#') {
        add = 1;
        if (lc>=0 && lc==pc) return -1;
        if (lc>=0) {
            Set(st, lc, x);
            if (pc>=0) {
                for(int i=0;i<w;i++) if (Get(st,i)==pc) Set(st, lc, i);
            }
        } else if (pc==-1) Set(st, 7, x);
        else Set(st, pc, x);
    } else {
        if ((y>0 && pc==-1) || (x>0 && lc==-1)) return -1;
        Set(st, -1, x);
        if (pc!=-1) {
            bool ok=false;
            for(int i=0;i<w;i++) if (Get(st,i)==pc){ ok=true; break; }
            if (!ok) return -1;
        }
    }
    memset(mapto, -1, sizeof(mapto));
    int mcnt=0;
    for(int i=0;i<w;i++){
        int v = Get(st,i);
        if (v!=-1) {
            if (mapto[v]==-1) mapto[v]=mcnt++;
            Set(st, mapto[v], i);
        }
    }
    int sub = calc(st, x+1, y);
    return sub<0 ? -1 : sub+add;
}

int main(){
    ios::sync_with_stdio(0);
    cin.tie(0);

    cin >> h >> w;
    for(int y=0;y<h;y++) cin >> B[y];
    if (w==1) {
        if (h==1) {
            cout << (B[0][0]=='.' ? 0 : 1) << endl;
            return 0;
        }
        int ans = -1;
        for(int L=0;L<=1;L++){
            for(int R=max(L,h-2); R<=h-1; R++){
                if (L>R) continue;
                bool ok = true;
                for(int i=L;i<=R;i++){
                    if (B[i][0]=='.') ok=false;
                }
                for(int i=0;i<L;i++){
                    if (B[i][0]=='#') ok=false;
                }
                for(int i=R+1;i<h;i++){
                    if (B[i][0]=='#') ok=false;
                }
                if (!ok) continue;
                ans = max(ans, R-L+1);
            }
        }
        cout << ans << endl;
        return 0;
    }
    for(int y=0;y<h;y++){
        for(int x=0;x<w;x++){
            memo[y][x].clear();
        }
    }
    int ans = calc(-1LL, 0, 0);
    cout << ans << endl;
    return 0;
}
accuracy: 1
time_ms: 90
memory_kb: 21292
final_rank: 4

code_snippet: #pragma GCC optimize("Ofast")
#include <bits/stdc++.h>
using namespace std;
typedef long long int ll;
typedef unsigned long long int ull;

mt19937_64 rng(chrono::steady_clock::now().time_since_epoch().count());
ll myRand(ll B) {
    return (ull)rng() % B;
}
inline double time() {
    return static_cast<long double>(chrono::duration_cast<chrono::nanoseconds>(chrono::steady_clock::now().time_since_epoch()).count()) * 1e-9;
}

int main() {
    cin.tie(nullptr);
    ios::sync_with_stdio(false);
    int h,w; cin >> h >> w;
    vector<string> s(h);
    for (int i = 0; i < h; ++i) {
        cin >> s[i];
    }
    map<vector<int>, int> dp;
    // そもそもw=1は除いておいた方が連結性確認の面で楽？
    if (w == 1) {
        for (int i = 1; i+1 < h; ++i) {
            if (s[i][0] == '.') {
                cout << -1 << endl;
                return 0;
            }
        }
        set<int> st;
        if (s[0][0] == '.') st.insert(0);
        if (s.back()[0] == '.') st.insert(h-1);
        cout << h - st.size() << endl;
        return 0;
    }
    {
        // 1列目の置き方を列挙する
        vector<int> v(w);
        auto dfs = [&](auto dfs, int i, int id, int cnt) -> void {
            if (i == w) {
                dp[v] = cnt;
                return;
            }
            if (v[i-1] == 0) {
                if (s[0][i] == '.') return;
                v[i] = id + 1;
                dfs(dfs, i+1, id+1, cnt+1);
            }
            else {
                v[i] = 0;
                if (s[0][i] != '#') dfs(dfs, i+1, id, cnt);
                v[i] = id;
                if (s[0][i] != '.') dfs(dfs, i+1, id, cnt+1);
            }
        };
        v[0] = 1;
        if (s[0][0] != '.') dfs(dfs, 1, 1, 1);
        v[0] = 0;
        if (s[0][0] != '#') dfs(dfs, 1, 0, 0);
    }
    for (int i = 1; i < h; ++i) {
        for (int j = 0; j < w; ++j) {
            map<vector<int>, int> ndp;
            bool B = (s[i][j] != '.');
            bool W = (s[i][j] != '#');
            if (B) {
                for (auto &pp : dp) {
                    auto p = pp.first;
                    // ループを作ってはいけない
                    if (j and p[j-1] and p[j-1] == p[j]) continue;
                    // 接する面が白のみの場合、新規連結成分
                    if (p[j] == 0 and (j == 0 or p[j-1] == 0)) {
                        int mx = 0;
                        for (int k = 0; k < w; ++k) {
                            mx = max(mx, p[k]);
                        }
                        p[j] = mx+1;
                        ndp[p] = max(ndp[p], pp.second+1);
                    } else {
                        if (j == 0 or p[j-1] == 0) {
                            // そのまま
                            ndp[p] = max(ndp[p], pp.second+1);
                        } else if (p[j] == 0) {
                            p[j] = p[j-1];
                            ndp[p] = max(ndp[p], pp.second+1);
                        } else {
                            int a = p[j], b = p[j-1];
                            if (a > b) swap(a, b);
                            // 2つをマージする
                            p[j] = a;
                            for (int k = 0; k < w; ++k) {
                                if (p[k] == b) p[k] = a;
                                else if (p[k] > b) p[k] -= 1;
                            }
                            ndp[p] = max(ndp[p], pp.second+1);
                        }
                    }
                }
            }
            if (W) {
                for (auto &pp : dp) {
                    auto p = pp.first;
                    // 白は連結してはいけない
                    if (p[j] == 0 or (j and p[j-1] == 0)) continue;
                    // 白によって連結成分が孤立してしまってもダメ
                    int cnt = 0;
                    for (int k = 0; k < w; ++k) {
                        cnt += (p[j] == p[k]);
                    }
                    if (cnt != 1) {
                        p[j] = 0;
                        ndp[p] = max(ndp[p], pp.second);
                    }
                }
            }
            swap(dp, ndp);

//            cout << i << " " << j << endl;
//            for (auto &pp : dp) {
//                auto p = pp.first;
//                for (int k : p) {
//                    cout << k << " ";
//                }
//                cout << endl;
//            }
        }
    }
    int res = -1;
    for (auto &pp : dp) {
        auto p = pp.first;
        bool ok = true;
        for (int i = 0; i < w; ++i) {
            if (p[i] > 1) ok = false;
        }
        if (ok) res = max(res, pp.second);
    }
    cout << res << endl;
}
accuracy: 1
time_ms: 320
memory_kb: 6100
final_rank: 7

code_snippet: #include <bits/stdc++.h>
using namespace std;

string to_string(const vector<int>& arr) {
	string res = "[";
	for (int i = 0; i < int(arr.size()); i++) {
		if (i != 0) {
			res += ", ";
		}
		res += to_string(arr[i]);
	}
	res += "]";
	return res;
}

void regularize(int n, vector<int>& v) {
	int cnt = 0;
	vector<int> tbl(n + 1, -1);
	for (int i = 0; i < n; i++) {
		if (v[i] != -1 && tbl[v[i]] == -1) {
			tbl[v[i]] = cnt++;
		}
	}
	for (int i = 0; i < n; i++) {
		if (v[i] != -1) {
			v[i] = tbl[v[i]];
		}
	}
}

int solve_one(int N, const vector<int>& X) {
	if (N == 1) {
		return (X[0] != 0);
	}
	if (N == 2) {
		int res = (X[0] != 0) + (X[1] != 0);
		return (res >= 1 ? res : -1);
	}
	for (int i = 1; i < N - 1; i++) {
		if (X[i] == 0) {
			return -1;
		}
	}
	return (N - 2) + (X[0] != 0) + (X[N - 1] != 0);
}

int solve(int H, int W, const vector<vector<int> >& A) {
	if (H < W) {
		vector<vector<int> > B(W, vector<int>(H));
		for (int i = 0; i < H; i++) {
			for (int j = 0; j < W; j++) {
				B[j][i] = A[i][j];
			}
		}
		return solve(W, H, B);
	}
	if (W == 1) {
		vector<int> X(H);
		for (int i = 0; i < H; i++) {
			X[i] = A[i][0];
		}
		return solve_one(H, X);
	}
	const int INF = 1012345678;
	vector<vector<map<vector<int>, int> > > dp(H, vector<map<vector<int>, int> >(W));
	vector<string> Z(H, string(W, '?'));
	auto calc = [&](auto& self, int x, int y, const vector<int>& v) -> int {
		if (x == H && y == 0) {
			if (*max_element(v.begin(), v.end()) >= 1) {
				return -INF;
			}
			return 0;
		}
		if (dp[x][y].find(v) != dp[x][y].end()) {
			return dp[x][y][v];
		}
		int nx = x, ny = y + 1;
		if (ny == W) {
			nx += 1;
			ny = 0;
		}
		int res = -INF;
		if (A[x][y] != 1 && (y == 0 || v[y - 1] != -1) && v[y] != -1) {
			// place white
			vector<int> nv = v;
			nv[y] = -1;
			if (find(nv.begin(), nv.end(), v[y]) != nv.end()) {
				Z[x][y] = '.';
				int subres = self(self, nx, ny, nv);
				res = max(res, subres);
			}
		}
		if (A[x][y] != 0 && (y == 0 || v[y] == -1 || v[y - 1] != v[y])) {
			// place black
			vector<int> nv = v;
			if ((y != 0 && v[y - 1] != -1) && v[y] != -1) {
				for (int i = 0; i < W; i++) {
					if (v[i] == v[y]) {
						nv[i] = v[y - 1];
					}
				}
			}
			else if ((y != 0 && v[y - 1] != -1) || v[y] != -1) {
				nv[y] = (v[y - 1] != -1 ? v[y - 1] : v[y]);
			}
			else {
				nv[y] = W;
			}
			regularize(W, nv);
			Z[x][y] = '#';
			int subres = self(self, nx, ny, nv);
			res = max(res, subres + 1);
		}
		dp[x][y][v] = res;
		return res;
	};
	int ans = -1;
	for (int i = 0; i < (1 << W); i++) {
		vector<int> v(W, -1);
		int cnt = -1, pre = -2, black = 0;
		bool flag = true;
		for (int j = 0; j < W; j++) {
			if ((i >> j) & 1) {
				if (A[0][j] == 0) {
					flag = false;
				}
				if (pre != j - 1) {
					cnt += 1;
				}
				v[j] = cnt;
				pre = j;
				Z[0][j] = '#';
				black += 1;
			}
			else {
				Z[0][j] = '.';
				if (A[0][j] == 1 || (j >= 1 && v[j - 1] == -1)) {
					flag = false;
				}
			}
		}
		if (flag) {
			int res = calc(calc, 1, 0, v);
			ans = max(ans, res + black);
		}
	}
	return ans;
}

bool check(int H, int W, const vector<vector<int> >& A) {
	vector<vector<bool> > vis(H, vector<bool>(W, false));
	auto check = [&](int x, int y) -> bool {
		return 0 <= x && x < H && 0 <= y && y < W && !vis[x][y] && A[x][y] == 1;
	};
	auto dfs = [&](auto& self, int x, int y) -> void {
		vis[x][y] = true;
		if (check(x, y - 1)) self(self, x, y - 1);
		if (check(x, y + 1)) self(self, x, y + 1);
		if (check(x - 1, y)) self(self, x - 1, y);
		if (check(x + 1, y)) self(self, x + 1, y);
	};
	int cnt = 0;
	for (int i = 0; i < H; i++) {
		for (int j = 0; j < W; j++) {
			if (A[i][j] == 1 && !vis[i][j]) {
				dfs(dfs, i, j);
				cnt += 1;
			}
		}
	}
	if (cnt >= 2) {
		return false;
	}
	int f = 0;
	for (int i = 0; i < H; i++) {
		for (int j = 0; j < W; j++) {
			if (A[i][j] == 1) {
				if (i >= 1 && A[i - 1][j] == 1) f -= 1;
				if (j >= 1 && A[i][j - 1] == 1) f -= 1;
				f += 1;
			}
			if (A[i][j] == 0) {
				if (i >= 1 && A[i - 1][j] == 0) return false;
				if (j >= 1 && A[i][j - 1] == 0) return false;
			}
		}
	}
	return cnt == 0 || f == 1;
}

bool testcase_check(int H, int W) {
	for (int i = 0; i < 1 << (H * W); i++) {
		vector<vector<int> > A(H, vector<int>(W));
		for (int j = 0; j < H * W; j++) {
			A[j / W][j % W] = ((i >> j) & 1);
		}
		bool res1 = (solve(H, W, A) != -1);
		bool res2 = check(H, W, A);
		if (res1 != res2) {
			vector<string> res(H);
			for (int i = 0; i < H; i++) {
				for (int j = 0; j < W; j++) {
					res[i] += (A[i][j] == 0 ? '.' : '#');
				}
			}
			cout << "H = " << H << ", W = " << W << ":" << endl;
			for (int i = 0; i < H; i++) {
				cout << res[i] << endl;
			}
			cout << "Returns: " << (res1 ? "true" : "false") << endl;
			cout << "Answer: " << (res2 ? "true" : "false") << endl;
			return false;
		}
	}
	return true;
}

int main() {
	/*
	for (int H = 1; H <= 5; H++) {
		for (int W = 1; W <= H; W++) {
			if (testcase_check(H, W)) {
				cout << "H = " << H << ", W = " << W << ": success!" << endl;
			}
		}
	}
	return 0;
	*/
	int H, W;
	cin >> H >> W;
	vector<vector<int> > A(H, vector<int>(W, -1));
	for (int i = 0; i < H; i++) {
		string s;
		cin >> s;
		for (int j = 0; j < W; j++) {
			if (s[j] == '.') A[i][j] = 0;
			if (s[j] == '#') A[i][j] = 1;
		}
	}
	int ans = solve(H, W, A);
	cout << ans << endl;
	return 0;
}
accuracy: 1
time_ms: 200
memory_kb: 43856
final_rank: 9

code_snippet: #include <bits/stdc++.h>
using namespace std;

void regularize(int n, vector<int>& v) {
	int cnt = 0;
	vector<int> tbl(n + 1, -1);
	for (int i = 0; i < n; i++) {
		if (v[i] != -1 && tbl[v[i]] == -1) {
			tbl[v[i]] = cnt++;
		}
	}
	for (int i = 0; i < n; i++) {
		if (v[i] != -1) {
			v[i] = tbl[v[i]];
		}
	}
}

int solve_one(int N, const vector<int>& X) {
	if (N == 1) {
		return (X[0] != 0);
	}
	for (int i = 1; i < N - 1; i++) {
		if (X[i] == 0) {
			return -1;
		}
	}
	return (N - 2) + (X[0] != 0) + (X[N - 1] != 0);
}

string to_string(const vector<int>& arr) {
	string res = "[";
	for (int i = 0; i < int(arr.size()); i++) {
		if (i != 0) {
			res += ", ";
		}
		res += to_string(arr[i]);
	}
	res += "]";
	return res;
}

int solve(int H, int W, const vector<vector<int> >& A) {
	if (H < W) {
		vector<vector<int> > B(W, vector<int>(H));
		for (int i = 0; i < H; i++) {
			for (int j = 0; j < W; j++) {
				B[j][i] = A[i][j];
			}
		}
		return solve(W, H, B);
	}
	if (W == 1) {
		vector<int> X(H);
		for (int i = 0; i < H; i++) {
			X[i] = A[i][0];
		}
		return solve_one(H, X);
	}
	const int INF = 1012345678;
	vector<vector<map<vector<int>, int> > > dp(H, vector<map<vector<int>, int> >(W));
	vector<string> Z(H, string(W, '?'));
	auto calc = [&](auto& self, int x, int y, const vector<int>& v) -> int {
		if (x == H && y == 0) {
			if (*max_element(v.begin(), v.end()) >= 1) {
				return -INF;
			}
			return 0;
		}
		if (dp[x][y].find(v) != dp[x][y].end()) {
			return dp[x][y][v];
		}
		int nx = x, ny = y + 1;
		if (ny == W) {
			nx += 1;
			ny = 0;
		}
		int res = -INF;
		if (A[x][y] != 1 && (y == 0 || v[y - 1] != -1) && v[y] != -1) {
			// place white
			vector<int> nv = v;
			nv[y] = -1;
			if (find(nv.begin(), nv.end(), v[y]) != nv.end()) {
				Z[x][y] = '.';
				int subres = self(self, nx, ny, nv);
				res = max(res, subres);
			}
		}
		if (A[x][y] != 0 && (y == 0 || v[y] == -1 || v[y - 1] != v[y])) {
			// place black
			vector<int> nv = v;
			if ((y != 0 && v[y - 1] != -1) && v[y] != -1) {
				for (int i = 0; i < W; i++) {
					if (v[i] == v[y]) {
						nv[i] = v[y - 1];
					}
				}
			}
			else if ((y != 0 && v[y - 1] != -1) || v[y] != -1) {
				nv[y] = (v[y - 1] != -1 ? v[y - 1] : v[y]);
			}
			else {
				nv[y] = W;
			}
			regularize(W, nv);
			Z[x][y] = '#';
			int subres = self(self, nx, ny, nv);
			res = max(res, subres + 1);
		}
		dp[x][y][v] = res;
		return res;
	};
	int ans = -1;
	for (int i = 0; i < (1 << W); i++) {
		vector<int> v(W, -1);
		int cnt = -1, pre = -2, black = 0;
		bool flag = true;
		for (int j = 0; j < W; j++) {
			if ((i >> j) & 1) {
				if (A[0][j] == 0) {
					flag = false;
				}
				if (pre != j - 1) {
					cnt += 1;
				}
				v[j] = cnt;
				pre = j;
				Z[0][j] = '#';
				black += 1;
			}
			else {
				Z[0][j] = '.';
				if (A[0][j] == 1 || (j >= 1 && v[j - 1] == -1)) {
					flag = false;
				}
			}
		}
		if (flag) {
			int res = calc(calc, 1, 0, v);
			ans = max(ans, res + black);
		}
	}
	return ans;
}

int main() {
	int H, W;
	cin >> H >> W;
	vector<vector<int> > A(H, vector<int>(W, -1));
	for (int i = 0; i < H; i++) {
		string s;
		cin >> s;
		for (int j = 0; j < W; j++) {
			if (s[j] == '.') A[i][j] = 0;
			if (s[j] == '#') A[i][j] = 1;
		}
	}
	int ans = solve(H, W, A);
	cout << ans << endl;
	return 0;
}
accuracy: 0.6320754716981132
time_ms: 210
memory_kb: 43976
final_rank: 13

code_snippet: #include <bits/stdc++.h>
using namespace std;
typedef long long ll;
template<class T>bool chmax(T &a, const T &b) { if (a<b) { a=b; return true; } return false; }
template<class T>bool chmin(T &a, const T &b) { if (b<a) { a=b; return true; } return false; }
#define all(x) (x).begin(),(x).end()
#define fi first
#define se second
#define mp make_pair
#define si(x) ll(x.size())
const int mod=998244353,MAX=300005,INF=1<<30;

#define int short

int H,W;

vector<int> used;
vector<vector<int>> conne;
vector<int> nex;

vector<int> X;

ll pat=0;

void DFS(int rem){
    if(rem==0){
        pat++;
        used.push_back(nex.back());
        conne.push_back(X);
        return;
    }
    int s=-1;
    for(int j=0;;j++){
        if(rem&(1<<j)){
            s=(1<<j);
            break;
        }
    }
    for(int mask=rem;;mask=(mask-1)&rem){
        if(mask&s){
            int ng=0;
            for(int j=0;j<W;j++){
                if(mask&(1<<j)){
                    if(rem&(1<<(j+1))){
                        if(!(mask&(1<<(j+1)))) ng++;
                    }
                    if(j&&(rem&(1<<(j-1)))){
                        if(!(mask&(1<<(j-1)))) ng++;
                    }
                }
            }
            if(ng<=1){
                X.push_back(mask);
                DFS(rem-mask);
                X.pop_back();
            }
        }
        
        if(mask==0) break;
    }
}

int dp[12][12][233000];

vector<int> divide[233000];

signed main(){
    
    std::ifstream in("text.txt");
    std::cin.rdbuf(in.rdbuf());
    cin.tie(0);
    ios::sync_with_stdio(false);
    
    cin>>H>>W;
    vector<string> S(H);
    for(int i=0;i<H;i++) cin>>S[i];
    
    if(W==1){
        int ans=-1;
        {
            bool ok=true;
            for(int i=0;i<H-1;i++){
                ok&=(S[i][0]!='.');
            }
            ok&=(S[H-1][0]!='#');
            if(ok){
                if(ans<H-1) ans=H-1;
            }//chmax(ans,H-1);
        }
        {
            bool ok=true;
            for(int i=1;i<H;i++){
                ok&=(S[i][0]!='.');
            }
            ok&=(S[0][0]!='#');
            if(ok){
                if(ans<H-1) ans=H-1;
            }//chmax(ans,H-1);
        }
        {
            bool ok=true;
            for(int i=1;i<H-1;i++){
                ok&=(S[i][0]!='.');
            }
            ok&=(S[0][0]!='#');
            ok&=(S[H-1][0]!='#');
            //if(H!=2&&ok) chmax(ans,H-2);
            if(H!=2&&ok){
                if(ans<H-2) ans=H-2;
            }//chmax(ans,H-1);
        }
        {
            bool ok=true;
            for(int i=0;i<H;i++){
                ok&=(S[i][0]!='.');
            }
            if(ok){
                if(ans<H) ans=H;
            }//chmax(ans,H-1);
        }
        
        cout<<ans<<endl;
        
        return 0;
    }
    
    for(int bit=0;bit<(1<<W);bit++){
        //cout<<bit<<endl;
        int ng=0;
        for(int j=0;j+1<W;j++){
            int cn=0;
            if(bit&(1<<j)) cn++;
            if(bit&(1<<(j+1))) cn++;
            if(cn==0) ng++;
        }
        if(ng<=1){
            nex.push_back(bit);
            DFS(bit);
            
            vector<int> Y;
            int j=0;
            while(j<W){
                if(bit&(1<<j)){
                    int k=j;
                    int mas=0;
                    while(bit&(1<<k)){
                        mas|=(1<<k);
                        k++;
                    }
                    Y.push_back(mas);
                    j=k;
                }else{
                    j++;
                }
            }
            
            divide[bit]=Y;
            
            //cout<<bitset<10>(bit)<<endl;
        }
    }
    
    //cout<<si(conne)<<" "<<si(used)<<endl;
    //cout<<pat<<endl;
    
    for(ll j=0;j<si(conne);j++){
        sort(all(conne[j]));
        //cout<<bitset<10>(used[j])<<endl;
    }
    
    for(int i=0;i<=H;i++) for(int w=0;w<=W;w++) for(ll j=0;j<si(conne);j++) dp[i][w][j]=-100;
    
    map<vector<int>,ll> MA;
    
    for(ll t=0;t<si(conne);t++){
        MA[conne[t]]=t;
        bool ok=true;
        for(int j=0;j<W;j++){
            if(S[0][j]=='#'){
                if(!(used[t]&(1<<j))) ok=false;
            }
            if(S[0][j]=='.'){
                if(used[t]&(1<<j)) ok=false;
            }
        }
        for(int j=0;j+1<W;j++){
            int cn=0;
            if(!(used[t]&(1<<j))) cn++;
            if(!(used[t]&(1<<(j+1)))) cn++;
            if(cn==2) ok=false;
        }
        if(ok){
            if(divide[used[t]]==conne[t]){
                dp[1][0][t]=__builtin_popcount(used[t]);
                //cout<<bitset<11>(used[t])<<endl;
            }
        }
    }
    
    for(int i=1;i<H;i++){
        for(int j=0;j<W;j++){
            for(ll k=0;k<si(conne);k++){
                if(dp[i][j][k]<0) continue;
                
                int mask=used[k];
                
                if(mask&(1<<j)){
                    if(j==0||(!(mask&(1<<(j-1))))){
                        if(S[i][j]!='.'){
                            if(dp[i][j+1][k]<dp[i][j][k]+1) dp[i][j+1][k]=dp[i][j][k]+1;
                            //chmax(dp[i][j+1][k],dp[i][j][k]+1);
                        }
                    }else{
                        bool ok=true;
                        for(int a:conne[k]){
                            if((a&(1<<(j-1)))&&(a&(1<<j))) ok=false;
                        }
                        if(ok){
                            vector<int> to;
                            int ss=0;
                            for(int a:conne[k]){
                                if(a&(1<<(j-1))){
                                    ss|=a;
                                }else if(a&(1<<j)){
                                    ss|=a;
                                }else{
                                    to.push_back(a);
                                }
                            }
                            to.push_back(ss);
                            sort(all(to));
                            if(S[i][j]!='.'){
                                if(dp[i][j+1][MA[to]]<dp[i][j][k]+1) dp[i][j+1][MA[to]]=dp[i][j][k]+1;
                                //chmax(dp[i][j+1][MA[to]],dp[i][j][k]+1);
                            }
                        }
                    }
                    
                    int z=-1;
                    for(int a:conne[k]){
                        if(a&(1<<j)) z=a;
                    }
                    int hi=-1;
                    for(int l=W-1;l>=0;l--){
                        if(z&(1<<l)){
                            hi=l;
                            break;
                        }
                    }
                    int x=(1<<j)-1;
                    
                    if((hi!=j)||(z&x)){
                        vector<int> to=conne[k];
                        for(int &a:to){
                            if(a&(1<<j)) a-=(1<<j);
                        }
                        //cout<<used[k]<<" "<<used[MA[to]]<<endl;
                        sort(all(to));
                        //cout<<used[k]<<" "<<used[MA[to]]<<endl;
                        if(S[i][j]!='#'&&(j==0||(used[k]&(1<<(j-1))))) chmax(dp[i][j+1][MA[to]],dp[i][j][k]);
                    }
                }else{
                    if(j==0||(!(mask&(1<<(j-1))))){
                        vector<int> to=conne[k];
                        to.push_back((1<<j));
                        sort(all(to));
                        assert(MA.count(to));
                        if(S[i][j]!='.'){
                            if(dp[i][j+1][MA[to]]<dp[i][j][k]+1) dp[i][j+1][MA[to]]=dp[i][j][k]+1;
                            //chmax(dp[i][j+1][MA[to]],dp[i][j][k]+1);
                        }
                        assert(MA.count(to));
                        //cout<<used[k]<<" "<<used[MA[to]]<<endl;
                        //for(int a:to) cout<<a<<" ";
                        //cout<<endl;
                    }else{
                        vector<int> to=conne[k];
                        for(int &a:to){
                            if(a&(1<<(j-1))) a|=(1<<j);
                        }
                        sort(all(to));
                        if(S[i][j]!='.'){
                            if(dp[i][j+1][MA[to]]<dp[i][j][k]+1) dp[i][j+1][MA[to]]=dp[i][j][k]+1;
                            //chmax(dp[i][j+1][MA[to]],dp[i][j][k]+1);
                        }
                    }
                }
            }
        }
        
        for(ll k=0;k<si(conne);k++) dp[i+1][0][k]=dp[i][W][k];
    }
    
    int ans=-1;
    
    for(ll k=0;k<si(conne);k++){
        if(si(conne[k])==1){
            //for(int a:conne[k]) cout<<a<<" ";
            //cout<<" : ";
            //cout<<dp[H][0][k]<<endl;
            chmax(ans,dp[H][0][k]);
        }
    }
    
    cout<<ans<<endl;
}
accuracy: 1
time_ms: 240
memory_kb: 113200
final_rank: 12

code_snippet: #include <bits/stdc++.h>
using namespace std;
typedef long long ll;
template<class T>bool chmax(T &a, const T &b) { if (a<b) { a=b; return true; } return false; }
template<class T>bool chmin(T &a, const T &b) { if (b<a) { a=b; return true; } return false; }
#define all(x) (x).begin(),(x).end()
#define fi first
#define se second
#define mp make_pair
#define si(x) ll(x.size())
const int mod=998244353,MAX=300005,INF=1<<30;

#define int short

int H,W;

vector<int> used;
vector<vector<int>> conne;
vector<int> nex;

vector<int> X;

ll pat=0;

void DFS(int rem){
    if(rem==0){
        pat++;
        used.push_back(nex.back());
        conne.push_back(X);
        return;
    }
    int s=-1;
    for(int j=0;;j++){
        if(rem&(1<<j)){
            s=(1<<j);
            break;
        }
    }
    for(int mask=rem;;mask=(mask-1)&rem){
        if(mask&s){
            int ng=0;
            for(int j=0;j<W;j++){
                if(mask&(1<<j)){
                    if(rem&(1<<(j+1))){
                        if(!(mask&(1<<(j+1)))) ng++;
                    }
                    if(j&&(rem&(1<<(j-1)))){
                        if(!(mask&(1<<(j-1)))) ng++;
                    }
                }
            }
            if(ng<=1){
                X.push_back(mask);
                DFS(rem-mask);
                X.pop_back();
            }
        }
        
        if(mask==0) break;
    }
}

int dp[12][12][233000];

vector<int> divide[233000];

signed main(){
    
    std::ifstream in("text.txt");
    std::cin.rdbuf(in.rdbuf());
    cin.tie(0);
    ios::sync_with_stdio(false);
    
    cin>>H>>W;
    vector<string> S(H);
    for(int i=0;i<H;i++) cin>>S[i];
    
    if(W==1){
        int ans=-1;
        {
            bool ok=true;
            for(int i=0;i<H-1;i++){
                ok&=(S[i][0]!='.');
            }
            ok&=(S[H-1][0]!='#');
            if(ok){
                if(ans<H-1) ans=H-1;
            }//chmax(ans,H-1);
        }
        {
            bool ok=true;
            for(int i=1;i<H;i++){
                ok&=(S[i][0]!='.');
            }
            ok&=(S[0][0]!='#');
            if(ok){
                if(ans<H-1) ans=H-1;
            }//chmax(ans,H-1);
        }
        {
            bool ok=true;
            for(int i=1;i<H-1;i++){
                ok&=(S[i][0]!='.');
            }
            ok&=(S[0][0]!='#');
            ok&=(S[H-1][0]!='#');
            //if(H!=2&&ok) chmax(ans,H-2);
            if(H!=2&&ok){
                if(ans<H-2) ans=H-2;
            }//chmax(ans,H-1);
        }
        {
            bool ok=true;
            for(int i=0;i<H;i++){
                ok&=(S[i][0]!='.');
            }
            if(ok){
                if(ans<H) ans=H;
            }//chmax(ans,H-1);
        }
        
        cout<<ans<<endl;
        
        return 0;
    }
    
    for(int bit=0;bit<(1<<W);bit++){
        //cout<<bit<<endl;
        int ng=0;
        for(int j=0;j+1<W;j++){
            int cn=0;
            if(bit&(1<<j)) cn++;
            if(bit&(1<<(j+1))) cn++;
            if(cn==0) ng++;
        }
        if(ng<=1){
            nex.push_back(bit);
            DFS(bit);
            
            vector<int> Y;
            int j=0;
            while(j<W){
                if(bit&(1<<j)){
                    int k=j;
                    int mas=0;
                    while(bit&(1<<k)){
                        mas|=(1<<k);
                        k++;
                    }
                    Y.push_back(mas);
                    j=k;
                }else{
                    j++;
                }
            }
            
            divide[bit]=Y;
            
            //cout<<bitset<10>(bit)<<endl;
        }
    }
    
    //cout<<si(conne)<<" "<<si(used)<<endl;
    //cout<<pat<<endl;
    
    for(ll j=0;j<si(conne);j++){
        sort(all(conne[j]));
        //cout<<bitset<10>(used[j])<<endl;
    }
    
    for(int i=0;i<=H;i++) for(int w=0;w<=W;w++) for(ll j=0;j<si(conne);j++) dp[i][w][j]=-100;
    
    map<vector<int>,ll> MA;
    
    for(ll t=0;t<si(conne);t++){
        MA[conne[t]]=t;
        bool ok=true;
        for(int j=0;j<W;j++){
            if(S[0][j]=='#'){
                if(!(used[t]&(1<<j))) ok=false;
            }
            if(S[0][j]=='.'){
                if(used[t]&(1<<j)) ok=false;
            }
        }
        if(ok){
            if(divide[used[t]]==conne[t]){
                dp[1][0][t]=__builtin_popcount(used[t]);
                //cout<<used[t]<<endl;
            }
        }
    }
    
    for(int i=1;i<H;i++){
        for(int j=0;j<W;j++){
            for(ll k=0;k<si(conne);k++){
                if(dp[i][j][k]<0) continue;
                
                int mask=used[k];
                
                if(mask&(1<<j)){
                    if(j==0||(!(mask&(1<<(j-1))))){
                        if(S[i][j]!='.'){
                            if(dp[i][j+1][k]<dp[i][j][k]+1) dp[i][j+1][k]=dp[i][j][k]+1;
                            //chmax(dp[i][j+1][k],dp[i][j][k]+1);
                        }
                    }else{
                        bool ok=true;
                        for(int a:conne[k]){
                            if((a&(1<<(j-1)))&&(a&(1<<j))) ok=false;
                        }
                        if(ok){
                            vector<int> to;
                            int ss=0;
                            for(int a:conne[k]){
                                if(a&(1<<(j-1))){
                                    ss|=a;
                                }else if(a&(1<<j)){
                                    ss|=a;
                                }else{
                                    to.push_back(a);
                                }
                            }
                            to.push_back(ss);
                            sort(all(to));
                            if(S[i][j]!='.'){
                                if(dp[i][j+1][MA[to]]<dp[i][j][k]+1) dp[i][j+1][MA[to]]=dp[i][j][k]+1;
                                //chmax(dp[i][j+1][MA[to]],dp[i][j][k]+1);
                            }
                        }
                    }
                    
                    int z=-1;
                    for(int a:conne[k]){
                        if(a&(1<<j)) z=a;
                    }
                    int hi=-1;
                    for(int l=W-1;l>=0;l--){
                        if(z&(1<<l)){
                            hi=l;
                            break;
                        }
                    }
                    int x=(1<<j)-1;
                    
                    if((hi!=j)||(z&x)){
                        vector<int> to=conne[k];
                        for(int &a:to){
                            if(a&(1<<j)) a-=(1<<j);
                        }
                        //cout<<used[k]<<" "<<used[MA[to]]<<endl;
                        sort(all(to));
                        //cout<<used[k]<<" "<<used[MA[to]]<<endl;
                        if(S[i][j]!='#'&&(j==0||(used[k]&(1<<(j-1))))) chmax(dp[i][j+1][MA[to]],dp[i][j][k]);
                    }
                }else{
                    if(j==0||(!(mask&(1<<(j-1))))){
                        vector<int> to=conne[k];
                        to.push_back((1<<j));
                        sort(all(to));
                        assert(MA.count(to));
                        if(S[i][j]!='.'){
                            if(dp[i][j+1][MA[to]]<dp[i][j][k]+1) dp[i][j+1][MA[to]]=dp[i][j][k]+1;
                            //chmax(dp[i][j+1][MA[to]],dp[i][j][k]+1);
                        }
                        assert(MA.count(to));
                        //cout<<used[k]<<" "<<used[MA[to]]<<endl;
                        //for(int a:to) cout<<a<<" ";
                        //cout<<endl;
                    }else{
                        vector<int> to=conne[k];
                        for(int &a:to){
                            if(a&(1<<(j-1))) a|=(1<<j);
                        }
                        sort(all(to));
                        if(S[i][j]!='.'){
                            if(dp[i][j+1][MA[to]]<dp[i][j][k]+1) dp[i][j+1][MA[to]]=dp[i][j][k]+1;
                            //chmax(dp[i][j+1][MA[to]],dp[i][j][k]+1);
                        }
                    }
                }
            }
        }
        
        for(ll k=0;k<si(conne);k++) dp[i+1][0][k]=dp[i][W][k];
    }
    
    int ans=-1;
    
    for(ll k=0;k<si(conne);k++){
        if(si(conne[k])==1){
            //for(int a:conne[k]) cout<<a<<" ";
            //cout<<" : ";
            //cout<<dp[H][0][k]<<endl;
            chmax(ans,dp[H][0][k]);
        }
    }
    
    cout<<ans<<endl;
}
accuracy: 0.49056603773584906
time_ms: 250
memory_kb: 113052
final_rank: 15

code_snippet: #include <bits/stdc++.h>
using namespace std;
typedef long long ll;
template<class T>bool chmax(T &a, const T &b) { if (a<b) { a=b; return true; } return false; }
template<class T>bool chmin(T &a, const T &b) { if (b<a) { a=b; return true; } return false; }
#define all(x) (x).begin(),(x).end()
#define fi first
#define se second
#define mp make_pair
#define si(x) int(x.size())
const int mod=998244353,MAX=300005,INF=1<<30;

#define int short

int H,W;

vector<int> used;
vector<vector<int>> conne;
vector<int> nex;

vector<int> X;

ll pat=0;

void DFS(int rem){
    if(rem==0){
        pat++;
        used.push_back(nex.back());
        conne.push_back(X);
        return;
    }
    int s=-1;
    for(int j=0;;j++){
        if(rem&(1<<j)){
            s=(1<<j);
            break;
        }
    }
    for(int mask=rem;;mask=(mask-1)&rem){
        if(mask&s){
            int ng=0;
            for(int j=0;j<W;j++){
                if(mask&(1<<j)){
                    if(rem&(1<<(j+1))){
                        if(!(mask&(1<<(j+1)))) ng++;
                    }
                    if(j&&(rem&(1<<(j-1)))){
                        if(!(mask&(1<<(j-1)))) ng++;
                    }
                }
            }
            if(ng<=1){
                X.push_back(mask);
                DFS(rem-mask);
                X.pop_back();
            }
        }
        
        if(mask==0) break;
    }
}

int dp[12][12][233000];

vector<int> divide[233000];

signed main(){
    
    std::ifstream in("text.txt");
    std::cin.rdbuf(in.rdbuf());
    cin.tie(0);
    ios::sync_with_stdio(false);
    
    cin>>H>>W;
    vector<string> S(H);
    for(int i=0;i<H;i++) cin>>S[i];
    
    if(W==1){
        int ans=-1;
        {
            bool ok=true;
            for(int i=0;i<H-1;i++){
                ok&=(S[i][0]!='.');
            }
            ok&=(S[H-1][0]!='#');
            if(ok){
                if(ans<H-1) ans=H-1;
            }//chmax(ans,H-1);
        }
        {
            bool ok=true;
            for(int i=1;i<H;i++){
                ok&=(S[i][0]!='.');
            }
            ok&=(S[0][0]!='#');
            if(ok){
                if(ans<H-1) ans=H-1;
            }//chmax(ans,H-1);
        }
        {
            bool ok=true;
            for(int i=1;i<H-1;i++){
                ok&=(S[i][0]!='.');
            }
            ok&=(S[0][0]!='#');
            ok&=(S[H-1][0]!='#');
            //if(H!=2&&ok) chmax(ans,H-2);
            if(H!=2&&ok){
                if(ans<H-2) ans=H-2;
            }//chmax(ans,H-1);
        }
        {
            bool ok=true;
            for(int i=0;i<H;i++){
                ok&=(S[i][0]!='.');
            }
            if(ok){
                if(ans<H) ans=H;
            }//chmax(ans,H-1);
        }
        
        cout<<ans<<endl;
        
        return 0;
    }
    
    for(int bit=0;bit<(1<<W);bit++){
        int ng=0;
        for(int j=0;j+1<W;j++){
            int cn=0;
            if(bit&(1<<j)) cn++;
            if(bit&(1<<(j+1))) cn++;
            if(cn==0) ng++;
        }
        if(ng<=1){
            nex.push_back(bit);
            DFS(bit);
            
            vector<int> Y;
            int j=0;
            while(j<W){
                if(bit&(1<<j)){
                    int k=j;
                    int mas=0;
                    while(bit&(1<<k)){
                        mas|=(1<<k);
                        k++;
                    }
                    Y.push_back(mas);
                    j=k;
                }else{
                    j++;
                }
            }
            
            divide[bit]=Y;
        }
    }
    
    //cout<<pat<<endl;
    
    for(int j=0;j<si(conne);j++){
        sort(all(conne[j]));
    }
    
    for(int i=0;i<=H;i++) for(int w=0;w<=W;w++) for(int j=0;j<si(conne);j++) dp[i][w][j]=-100;
    
    map<vector<int>,int> MA;
    
    for(int t=0;t<si(conne);t++){
        MA[conne[t]]=t;
        bool ok=true;
        for(int j=0;j<W;j++){
            if(S[0][j]=='#'){
                if(!(used[t]&(1<<j))) ok=false;
            }
            if(S[0][j]=='.'){
                if(used[t]&(1<<j)) ok=false;
            }
        }
        if(ok){
            if(divide[used[t]]==conne[t]){
                dp[1][0][t]=__builtin_popcount(used[t]);
            }
        }
    }
    
    for(int i=1;i<H;i++){
        for(int j=0;j<W;j++){
            for(int k=0;k<si(conne);k++){
                if(dp[i][j][k]<0) continue;
                
                int mask=used[k];
                
                if(mask&(1<<j)){
                    if(j==0||(!(mask&(1<<(j-1))))){
                        if(S[i][j]!='.'){
                            if(dp[i][j+1][k]<dp[i][j][k]+1) dp[i][j+1][k]=dp[i][j][k]+1;
                            //chmax(dp[i][j+1][k],dp[i][j][k]+1);
                        }
                    }else{
                        bool ok=true;
                        for(int a:conne[k]){
                            if((a&(1<<(j-1)))&&(a&(1<<j))) ok=false;
                        }
                        if(ok){
                            vector<int> to;
                            int ss=0;
                            for(int a:conne[k]){
                                if(a&(1<<(j-1))){
                                    ss|=a;
                                }else if(a&(1<<j)){
                                    ss|=a;
                                }else{
                                    to.push_back(a);
                                }
                            }
                            to.push_back(ss);
                            sort(all(to));
                            if(S[i][j]!='.'){
                                if(dp[i][j+1][MA[to]]<dp[i][j][k]+1) dp[i][j+1][MA[to]]=dp[i][j][k]+1;
                                //chmax(dp[i][j+1][MA[to]],dp[i][j][k]+1);
                            }
                        }
                    }
                    
                    int z=-1;
                    for(int a:conne[k]){
                        if(a&(1<<j)) z=a;
                    }
                    int hi=-1;
                    for(int l=W-1;l>=0;l--){
                        if(z&(1<<l)){
                            hi=l;
                            break;
                        }
                    }
                    int x=(1<<j)-1;
                    
                    if((hi!=j)||(z&x)){
                        vector<int> to=conne[k];
                        for(int &a:to){
                            if(a&(1<<j)) a-=(1<<j);
                        }
                        //cout<<used[k]<<" "<<used[MA[to]]<<endl;
                        sort(all(to));
                        //cout<<used[k]<<" "<<used[MA[to]]<<endl;
                        if(S[i][j]!='#'&&(j==0||(used[k]&(1<<(j-1))))) chmax(dp[i][j+1][MA[to]],dp[i][j][k]);
                    }
                }else{
                    if(j==0||(!(mask&(1<<(j-1))))){
                        vector<int> to=conne[k];
                        to.push_back((1<<j));
                        sort(all(to));
                        assert(MA.count(to));
                        if(S[i][j]!='.'){
                            if(dp[i][j+1][MA[to]]<dp[i][j][k]+1) dp[i][j+1][MA[to]]=dp[i][j][k]+1;
                            //chmax(dp[i][j+1][MA[to]],dp[i][j][k]+1);
                        }
                        assert(MA.count(to));
                        //cout<<used[k]<<" "<<used[MA[to]]<<endl;
                        //for(int a:to) cout<<a<<" ";
                        //cout<<endl;
                    }else{
                        vector<int> to=conne[k];
                        for(int &a:to){
                            if(a&(1<<(j-1))) a|=(1<<j);
                        }
                        sort(all(to));
                        if(S[i][j]!='.'){
                            if(dp[i][j+1][MA[to]]<dp[i][j][k]+1) dp[i][j+1][MA[to]]=dp[i][j][k]+1;
                            //chmax(dp[i][j+1][MA[to]],dp[i][j][k]+1);
                        }
                    }
                }
            }
        }
        
        for(int k=0;k<si(conne);k++) dp[i+1][0][k]=dp[i][W][k];
    }
    
    int ans=-1;
    
    for(int k=0;k<si(conne);k++){
        if(si(conne[k])==1){
            //for(int a:conne[k]) cout<<a<<" ";
            //cout<<" : ";
            //cout<<dp[H][0][k]<<endl;
            chmax(ans,dp[H][0][k]);
        }
    }
    
    cout<<ans<<endl;
}
accuracy: 0.20754716981132076
time_ms: 20
memory_kb: 71476
final_rank: 18

code_snippet: //#pragma GCC optimize("O3")
//#pragma GCC optimize("unroll-loops")
#include<iostream>
#include<string>
#include<cstdio>
#include<vector>
#include<cmath>
#include<algorithm>
#include<functional>
#include<iomanip>
#include<queue>
#include<ciso646>
#include<random>
#include<map>
#include<set>
#include<bitset>
#include<stack>
#include<unordered_map>
#include<unordered_set>
#include<utility>
#include<cassert>
#include<complex>
#include<numeric>
#include<array>
using namespace std;

//#define int long long
typedef long long ll;

typedef unsigned long long ul;
typedef unsigned int ui;
constexpr ll mod = 1000003;;
const ll INF = mod * mod;
typedef pair<int, int>P;

#define rep(i,n) for(int i=0;i<n;i++)
#define per(i,n) for(int i=n-1;i>=0;i--)
#define Rep(i,sta,n) for(int i=sta;i<n;i++)
#define rep1(i,n) for(int i=1;i<=n;i++)
#define per1(i,n) for(int i=n;i>=1;i--)
#define Rep1(i,sta,n) for(int i=sta;i<=n;i++)
#define all(v) (v).begin(),(v).end()
typedef pair<ll, ll> LP;
typedef long double ld;
typedef pair<ld, ld> LDP;
const ld eps = 1e-8;
const ld pi = acosl(-1.0);

ll mod_pow(ll x, ll n, ll m = mod) {
	if (n < 0) {
		ll res = mod_pow(x, -n, m);
		return mod_pow(res, m - 2, m);
	}
	if (abs(x) >= m)x %= m;
	if (x < 0)x += m;
	ll res = 1;
	while (n) {
		if (n & 1)res = res * x % m;
		x = x * x % m; n >>= 1;
	}
	return res;
}
struct modint {
	ll n;
	modint() :n(0) { ; }
	modint(ll m) :n(m) {
		if (n >= mod)n %= mod;
		else if (n < 0)n = (n % mod + mod) % mod;
	}
	operator int() { return n; }
};
bool operator==(modint a, modint b) { return a.n == b.n; }
modint operator+=(modint& a, modint b) { a.n += b.n; if (a.n >= mod)a.n -= mod; return a; }
modint operator-=(modint& a, modint b) { a.n -= b.n; if (a.n < 0)a.n += mod; return a; }
modint operator*=(modint& a, modint b) { a.n = ((ll)a.n * b.n) % mod; return a; }
modint operator+(modint a, modint b) { return a += b; }
modint operator-(modint a, modint b) { return a -= b; }
modint operator*(modint a, modint b) { return a *= b; }
modint operator^(modint a, ll n) {
	if (n == 0)return modint(1);
	modint res = (a * a) ^ (n / 2);
	if (n % 2)res = res * a;
	return res;
}

ll inv(ll a, ll p) {
	return (a == 1 ? 1 : (1 - p * inv(p % a, a)) / a + p);
}
modint operator/(modint a, modint b) { return a * modint(inv(b, mod)); }
modint operator/=(modint& a, modint b) { a = a / b; return a; }
const int max_n = 1 << 2;
modint fact[max_n], factinv[max_n];
void init_f() {
	fact[0] = modint(1);
	for (int i = 0; i < max_n - 1; i++) {
		fact[i + 1] = fact[i] * modint(i + 1);
	}
	factinv[max_n - 1] = modint(1) / fact[max_n - 1];
	for (int i = max_n - 2; i >= 0; i--) {
		factinv[i] = factinv[i + 1] * modint(i + 1);
	}
}
modint comb(int a, int b) {
	if (a < 0 || b < 0 || a < b)return 0;
	return fact[a] * factinv[b] * factinv[a - b];
}
modint combP(int a, int b) {
	if (a < 0 || b < 0 || a < b)return 0;
	return fact[a] * factinv[a - b];
}

void solve() {
	int h, w; cin >> h >> w;
	vector<string> s(h);
	rep(i, h)cin >> s[i];
	if (w == 1) {
		int ans = -1;
		rep(i, (1 << h)) {
			bool valid = true;
			vector<bool> c(h);
			rep(j, h) {
				int b = i & (1 << j);
				c[j] = b;
				if (b && s[j][0] == '.')valid = false;
				if (!b && s[j][0] == '#')valid = false;
			}
			rep(j, h - 1) {
				if (!c[j] && !c[j + 1])valid = false;
			}
			rep(j, h)if (c[j]) {
				while (j + 1 < h && c[j + 1])j++;
				j++; j++;
				for (; j < h; j++) {
					if (c[j])valid = false;
				}
			}
			if (!valid)continue;
			int cnt = 0;
			rep(j, h)if (c[j])cnt++;
			ans = max(ans, cnt);
		}
		cout << ans << "\n";
		return;
	}
	vector<vector<int>> ch(1 << w);
	rep(j, (1 << w)) {
		rep(i, w)if (j & (1 << i))ch[j].push_back(i);
	}
	vector<int> trans(w);
	vector<int> nv;

	map<vector<int>, int> dp;
	dp[{}] = 0;
	rep(i, h)rep(j, w) {
		map<vector<int>, int> ndp;
		for (auto p : dp) {
			fill(all(trans), -1);
			rep(i,p.first.size())for (int c : ch[p.first[i]]) {
				trans[c] = i;
			}
			//white,black
			rep(ad, 2) {
				if (ad == 0 && s[i][j] == '#')continue;
				if (ad == 1 && s[i][j] == '.')continue;
				bool valid = true;

				//white and white
				if (ad == 0) {
					if (i > 0 && trans[j]<0)valid = false;
					if (j > 0 && trans[j - 1]<0)valid = false;
				}
				//only one and die
				if (ad == 0) {
					if (trans[j] >= 0) {
						if (p.first[trans[j]] == (1 << j))valid = false;
					}
				}
				//black cycle
				if (ad == 1) {
					if (i > 0 && j > 0 && trans[j] >= 0 && trans[j - 1] >= 0 && trans[j] == trans[j - 1]) {
						valid = false;
					}
				}
				if (!valid)continue;
				nv.clear();
				if (ad == 0) {
					nv = p.first;
					if (trans[j] >= 0) {
						nv[trans[j]] ^= (1 << j);
					}
					sort(all(nv));
					if (nv.size() && nv[0] == 0)nv.erase(nv.begin());
				}
				else {
					nv = p.first;
					if (trans[j] < 0 && (j==0||trans[j - 1] < 0)) {
						nv.push_back(1 << j);
					}
					else if (trans[j] < 0) {
						nv[trans[j - 1]] |= (1 << j);
					}
					else if ((j==0||trans[j - 1] < 0)) {
						//
					}
					else {
						int a = trans[j];
						int b = trans[j - 1];
						nv[a] |= nv[b];
						nv.erase(nv.begin() + b);
					}
					sort(all(nv));
				}
				int val = p.second + ad;
				if (ndp.find(nv) != ndp.end()) {
					ndp[nv] = max(ndp[nv], val);
				}
				else {
					ndp[nv] = val;
				}
			}
		}
		swap(dp, ndp);
	}
	int ans = -1;
	for (auto p : dp) {
		if (p.first.size() <= 1)ans = max(ans, p.second);
	}
	cout << ans << "\n";
}


signed main() {
	ios::sync_with_stdio(false);
	cin.tie(0);
	cout << fixed << setprecision(8);
	//init_f();
	//init();
	//int t; cin >> t; rep(i, t)
	//while(cin>>n>>q,n)
	solve();
	return 0;
}
accuracy: 1
time_ms: 80
memory_kb: 4224
final_rank: 1

code_snippet: #include<bits/stdc++.h>
using namespace std;
using Int = long long;
template<typename T1,typename T2> inline void chmin(T1 &a,T2 b){if(a>b) a=b;}
template<typename T1,typename T2> inline void chmax(T1 &a,T2 b){if(a<b) a=b;}

//INSERT ABOVE HERE
struct UnionFind{
  vector<int> ps;
  UnionFind(int n):ps(n){iota(ps.begin(),ps.end(),0);}
  int find(int x){
    if(ps[x]==x) return x;
    return ps[x]=find(ps[x]);
  }
  int same(int x,int y){
    return find(x)==find(y);
  }
  void unite(int x,int y){
    x=find(x);y=find(y);
    if(x==y) return;
    if(x<y) swap(x,y);
    ps[y]=x;
  }
};

signed main(){
  int h,w;
  cin>>h>>w;
  vector<string> st(h);
  for(int i=0;i<h;i++) cin>>st[i];

  if(h==1&&w==1){
    if(st[0][0]=='.') cout<<0<<endl;
    else cout<<1<<endl;
    return 0;
  }

  if(w==1){
    vector<string> vs(w);
    for(int j=0;j<w;j++){
      vs[j]=string(h,'%');
      for(int i=0;i<h;i++) vs[j][i]=st[i][j];
    }
    swap(h,w);
    st=vs;
  }

  vector<int> bs(h,0),ws(h,0);
  for(int i=0;i<h;i++){
    for(int j=0;j<w;j++){
      bs[i]|=(st[i][j]=='#')<<j;
      ws[i]|=(st[i][j]=='.')<<j;
    }
  }

  int sz=1<<w;
  vector<int> cand;
  for(int bit=0;bit<sz;bit++){
    vector<int> vs(w);
    for(int j=0;j<w;j++)
      vs[j]=(bit>>j)&1;
    int flg=1;
    for(int j=0;j+1<w;j++)
      flg&=vs[j]||vs[j+1];
    if(flg) cand.emplace_back(bit);
  }

  map<vector<int>, int> dp;
  for(int bit:cand){
    if(( bit&bs[0])!=bs[0]) continue;
    if((~bit&ws[0])!=ws[0]) continue;

    vector<int> vs(w);
    for(int j=0;j<w;j++)
      vs[j]=(bit>>j)&1;

    UnionFind uf(w);
    for(int j=0;j+1<w;j++)
      if(vs[j]&&vs[j+1]) uf.unite(j,j+1);

    for(int j=0;j<w;j++) uf.find(j);
    vector<int> ps=uf.ps;
    for(int j=0;j<w;j++)
      if(!vs[j]) ps[j]=-1;

    dp[ps]=__builtin_popcount(bit);
  }

  for(int i=1;i<h;i++){
    map<vector<int>, int> nx;
    for(auto p:dp){
      vector<int> ps=p.first;
      for(int bit:cand){
        if(( bit&bs[i])!=bs[i]) continue;
        if((~bit&ws[i])!=ws[i]) continue;

        vector<int> vs(w);
        for(int j=0;j<w;j++)
          vs[j]=(bit>>j)&1;

        // cout<<i<<" "<<p.second<<":"<<bit<<endl;
        int ng=0;
        for(int j=0;j<w;j++)
          if(ps[j]<0&&!vs[j]) ng=1;
        if(ng) continue;

        UnionFind uf(w*2);
        for(int j=0;j+1<w;j++)
          if(vs[j]&&vs[j+1]) uf.unite(w+j,w+j+1);

        for(int j=0;j<w;j++)
          for(int k=0;k<w;k++)
            if(~ps[j]&&ps[j]==ps[k])
              uf.unite(j,k);

        for(int j=0;j<w;j++){
          if(ps[j]<0||!vs[j]) continue;
          if(uf.same(j,w+j)) ng=1;
          uf.unite(j,w+j);
        }
        if(ng) continue;

        for(int j=0;j<w*2;j++) uf.find(j);
        vector<int> qs=uf.ps;
        for(int j=0;j<w;j++)
          if(~ps[j]&&qs[j]<w) ng=1;
        if(ng) continue;

        vector<int> rs(w);
        for(int j=0;j<w;j++) rs[j]=qs[w+j]-w;
        for(int j=0;j<w;j++) if(!vs[j]) rs[j]=-1;
        nx[rs];
        chmax(nx[rs],p.second+__builtin_popcount(bit));
      }
    }
    swap(dp,nx);
  }

  int ans=-1;
  for(auto p:dp){
    vector<int> ps=p.first;
    set<int> ss;
    for(int j=0;j<w;j++)
      if(~ps[j]) ss.emplace(ps[j]);
    if(ss.size()==1)
      chmax(ans,p.second);
  }
  cout<<ans<<endl;
  return 0;
}
accuracy: 1
time_ms: 610
memory_kb: 3840
final_rank: 10

code_snippet: #include<bits/stdc++.h>
typedef long long int ll;
typedef unsigned long long int ull;
#define BIG_NUM 2000000000
#define HUGE_NUM 99999999999999999
#define MOD 1000000007
#define EPS 0.000000001
using namespace std;


#define NUM 15
#define UNDEFINED 0
#define WHITE 1

struct Info{
	Info(int arg_row,int arg_col){
		row = arg_row;
		col = arg_col;
	}
	int row,col;
};

int H,W;
int diff_row[4] = {-1,0,0,1},diff_col[4] = {0,-1,1,0};
int boss[NUM],height[NUM];
bool check[NUM][NUM],FLG;
char table[NUM][NUM];
map<ll,int> dp[NUM][NUM];
vector<Info> G[NUM][NUM];


//自分のボスのindexを取得しつつ、経路圧縮を行う関数
int get_boss(int id){
	if(boss[id] == id)return id; //自分が代表なら、自分の値を返す
	else{
		return boss[id] = get_boss(boss[id]); //代表でないなら、自分が所属する組織の代表を返しつつ、経路圧縮
	}
}

int is_same(int x,int y){
	return get_boss(x) == get_boss(y);
}

void unite(int x,int y){
	int boss_x = get_boss(x);
	int boss_y = get_boss(y);

	//既に同じグループなら何もしない
	if(boss_x == boss_y)return;

	//高さが高い方に吸収する
	if(height[x] > height[y]){

		boss[boss_y] = boss_x;

	}else if(height[x] < height[y]){

		boss[boss_x] = boss_y;

	}else{ //height[x] == height[y]

		boss[boss_y] = boss_x;
		height[x]++;
	}
}


bool rangeCheck(int row,int col){

	return row >= 0 && row <= H-1 && col >= 0 && col <= W-1;
}

ll get_code(ll array[NUM]){

	ll ret = 0;

	for(int i = 0; i < W; i++){

		ret = 10*ret+array[i];
	}

	return ret;
}

bool is_ok(ll array[NUM]){

	//白マスが連続していないか調べる
	for(int col = 0; col < W-1; col++){

		if(array[col] == WHITE && array[col+1] == WHITE){

			return false;
		}
	}

	//任意の2つの黒セル間には1本だけ経路がある→グループは1つでなければならない
	for(int col = 0; col < W; col++){
		if(array[col] >= 3){

			return false;
		}
	}

	return true;
}

void rename(ll array[NUM]){

	ll check[100];

	for(int i = 0; i < 100; i++){

		check[i] = -1;
	}

	ll next_id = 2;

	for(int i = 0; i < W; i++){
		if(array[i] == UNDEFINED || array[i] == WHITE)continue;

		if(check[array[i]] == -1){
			check[array[i]] = next_id++;
		}
	}

	for(int i = 0; i < W; i++){
		if(array[i] == UNDEFINED || array[i] == WHITE)continue;
		array[i] = check[array[i]];
	}
}

int recursive(int row,int col,ll array[NUM],int last_group){

	if(row == H){

		if(is_ok(array)){

			return 0;

		}else{

			return -BIG_NUM;
		}
	}

	ll tmp_code = get_code(array);

	auto at = dp[row][col].find(tmp_code); //dpは、この状態から見て、これから未来に得られる最大値を持つ
	if(at != dp[row][col].end()){

		return dp[row][col][tmp_code];
	}

	int next_row,next_col,next_last_group = last_group;
	ll next_array[2][NUM];

	//次のrowとcolを設定
	if(col == W-1){

		next_row = row+1;
		next_col = 0;

	}else{

		next_row = row;
		next_col = col+1;
	}

	for(int i = 0; i < 2; i++){
		for(int a = 0; a < W; a++){
			next_array[i][a] = array[a];
		}
	}
	int ret = -BIG_NUM;

	//今回のマスを黒にする
	if(table[row][col] == '#' || table[row][col] == '?'){

		if(col > 0 && next_array[0][col-1] != WHITE && //左が黒
				next_array[0][col] != WHITE && next_array[0][col] != UNDEFINED && //上が黒
				next_array[0][col-1] == next_array[0][col]){ //左と右が同じグループ

			//Do nothing:閉路ができてしまうので黒で塗れない

		}else{

			if(col == 0 || next_array[0][col-1] == WHITE){ //左端、または左が白→左方に黒はない

				switch(next_array[0][col]){
				case UNDEFINED: //左にも上にも黒はない
				case WHITE:
					next_array[0][col] = next_last_group++; //新しいグループを作る
					break;
				default: //上のマスが黒
					//Do nothing:上のマスと同じグループにする
					break;
				}

				rename(next_array[0]);

				ret = max(ret,recursive(next_row,next_col,next_array[0],next_last_group)+1);

			}else{ //col >= 1 && array[col-1] == BLACK

				switch(next_array[0][col]){
				case UNDEFINED:
				case WHITE:
					next_array[0][col] = next_array[0][col-1]; //左のgroupと同じにする
					break;
				default: //上のマスが黒:上のマスと左のマスは異なるグループであるはず

					int new_id = next_array[0][col]; //★今回のマスの番号を新しいIDとして使用★
					int old_id = next_array[0][col-1];

					for(int a = 0; a < W; a++){ //同じIDが飛んで存在する場合あり
						if(next_array[0][a] == old_id){

							next_array[0][a] = new_id;
						}
					}

					break;
				}

				rename(next_array[0]);

				ret = max(ret,recursive(next_row,next_col,next_array[0],next_last_group)+1);

			}
		}
	}

	next_last_group = last_group;

	//今回のマスを白にする
	if(table[row][col] == '.' || table[row][col] == '?'){

		 if(next_array[1][col] == WHITE || (col > 0 && next_array[1][col-1] == WHITE)){ //上か左が白

			  //Do nothing:白が連続するので不可

		 }else{ //上にも左にも白はない

			 if(next_array[1][col] != UNDEFINED){ //上のマスが黒

				int count = 0;

				for(int a = 0; a < W; a++){
					if(next_array[1][a] == array[col]){
						count++;
					}
				}

				if(count == 1){
					//Do nothing:上のマスが孤立するので不可
				}else{

					//上のマスが黒で、左に白がない

					next_array[1][col] = WHITE;

					rename(next_array[1]);

					ret = max(ret,recursive(next_row,next_col,next_array[1],next_last_group));
				}

			 }else{

				 //上のマスがUNDFINEDで、左に白がない

				 next_array[1][col] = WHITE;

				 rename(next_array[1]);

				 ret = max(ret,recursive(next_row,next_col,next_array[1],next_last_group));
			 }
		 }
	}

	return dp[row][col][tmp_code] = ret;
}

void dfs(int row,int col,int pre_row,int pre_col){

	if(!FLG)return;

	int next_row,next_col;

	for(int i = 0; i < G[row][col].size(); i++){

		next_row = G[row][col][i].row;
		next_col = G[row][col][i].col;

		if(next_row == pre_row && next_col == pre_col)continue;

		if(check[next_row][next_col]){ //有向に遷移しているので、一度訪れた頂点をまた訪れたら閉路あり

			FLG = false;
			return;
		}
		check[next_row][next_col] = true;

		dfs(next_row,next_col,row,col);
	}
}


int main(){

	scanf("%d %d",&H,&W);

	for(int row = 0; row < H; row++){

		scanf("%s",table[row]);
	}

	//ややこしいので例外処理
	if(H == 1 || W == 1){

		if(H == 1 && W == 1){

			switch(table[0][0]){
			case '.':
				printf("0\n");
				break;
			case '#':
				printf("1\n");
				break;
			case '?':
				printf("1\n");
				break;
			}

			return 0;

		}else if(H == 1){

			//白ますが連続していたら不可
			for(int col = 0; col < W-1; col++){
				if(table[0][col] == '.' && table[0][col+1] == '.'){
					printf("-1\n");
					return 0;
				}
			}

			int ans = 0;

			//とりあえず?のところを前部黒にして、連結しているか調べる
			for(int col = 0; col < W; col++){
				if(table[0][col] == '?'){
					table[0][col] = '#';
					ans++;
				}else if(table[0][col] == '#'){
					ans++;
				}
			}

			for(int i = 0; i < W; i++){

				boss[i] = i;
				height[i] = 0;
			}

			for(int col = 0; col < W-1; col++){
				if(table[0][col] == '#' && table[0][col+1] == '#'){
					unite(col,col+1);
				}
			}

			int num_group = 0;

			for(int col = 0; col < W; col++){
				if(table[0][col] == '#'){
					if(get_boss(col) == col){
						num_group++;
					}
				}
			}

			if(num_group >= 2){

				printf("-1\n");

			}else{

				printf("%d\n",ans);
			}

			return 0;

		}else{ //W == 1


			//白ますが連続していたら不可
			for(int row = 0; row < H-1; row++){
				if(table[row][0] == '.' && table[row+1][0] == '.'){
					printf("-1\n");
					return 0;
				}
			}

			int ans = 0;

			//とりあえず?のところを前部黒にして、連結しているか調べる
			for(int row = 0; row < H; row++){
				if(table[row][0] == '?'){
					table[row][0] = '#';
					ans++;
				}else if(table[row][0] == '#'){
					ans++;
				}
			}

			for(int i = 0; i < H; i++){

				boss[i] = i;
				height[i] = 0;
			}

			for(int row = 0; row < H-1; row++){
				if(table[row][0] == '#' && table[row+1][0] == '#'){
					unite(row,row+1);
				}
			}

			int num_group = 0;

			for(int row = 0; row < H; row++){
				if(table[row][0] == '#'){
					if(get_boss(row) == row){
						num_group++;
					}
				}
			}

			if(num_group >= 2){

				printf("-1\n");

			}else{

				printf("%d\n",ans);
			}
			return 0;
		}
	}

	int adj_row,adj_col;

	//最初から閉路ができてないか調べる(dfsで調べるため、エッジを作る)
	for(int row = 0; row < H; row++){
		for(int col = 0; col < W; col++){
			if(table[row][col] != '#')continue;

			for(int i = 0; i < 4; i++){

				adj_row = row+diff_row[i];
				adj_col = col+diff_col[i];

				if(rangeCheck(adj_row,adj_col) == false || table[adj_row][adj_col] != '#')continue;

				G[row][col].push_back(Info(adj_row,adj_col));
			}
		}
	}

	for(int row = 0; row < H; row++){
		for(int col = 0; col < W; col++){
			if(table[row][col] != '#')continue;

			for(int a = 0; a < H; a++){
				for(int b = 0; b < W; b++){
					check[a][b] = false;
				}
			}

			check[row][col] = true;
			FLG= true;

			dfs(row,col,-1,-1);

			if(!FLG){

				printf("-1\n");
				return 0;
			}
		}
	}

	ll first_array[NUM];

	for(int i = 0; i < W; i++){

		first_array[i] = UNDEFINED;
	}

	int ret = recursive(0,0,first_array,2);

	if(ret < 0){

		printf("-1\n");
	}else{

		printf("%d\n",ret);
	}

	return 0;
}
accuracy: 1
time_ms: 120
memory_kb: 21092
final_rank: 6

code_snippet: #include<bits/stdc++.h>
typedef long long int ll;
typedef unsigned long long int ull;
#define BIG_NUM 2000000000
#define HUGE_NUM 99999999999999999
#define MOD 1000000007
#define EPS 0.000000001
using namespace std;


#define NUM 15
#define UNDEFINED 0
#define WHITE 1

struct Info{
	Info(int arg_row,int arg_col){
		row = arg_row;
		col = arg_col;
	}
	int row,col;
};

int H,W;
int diff_row[4] = {-1,0,0,1},diff_col[4] = {0,-1,1,0};
int boss[NUM],height[NUM];
bool check[NUM][NUM],FLG;
char table[NUM][NUM];
map<ll,int> dp[NUM][NUM];
vector<Info> G[NUM][NUM];


//自分のボスのindexを取得しつつ、経路圧縮を行う関数
int get_boss(int id){
	if(boss[id] == id)return id; //自分が代表なら、自分の値を返す
	else{
		return boss[id] = get_boss(boss[id]); //代表でないなら、自分が所属する組織の代表を返しつつ、経路圧縮
	}
}

int is_same(int x,int y){
	return get_boss(x) == get_boss(y);
}

void unite(int x,int y){
	int boss_x = get_boss(x);
	int boss_y = get_boss(y);

	//既に同じグループなら何もしない
	if(boss_x == boss_y)return;

	//高さが高い方に吸収する
	if(height[x] > height[y]){

		boss[boss_y] = boss_x;

	}else if(height[x] < height[y]){

		boss[boss_x] = boss_y;

	}else{ //height[x] == height[y]

		boss[boss_y] = boss_x;
		height[x]++;
	}
}


bool rangeCheck(int row,int col){

	return row >= 0 && row <= H-1 && col >= 0 && col <= W-1;
}

ll get_code(int array[NUM]){

	ll ret = 0;

	for(int i = 0; i < W; i++){

		ret = 10*ret+array[i];
	}

	return ret;
}

bool is_ok(int array[NUM]){

	//白マスが連続していないか調べる
	for(int col = 0; col < W-1; col++){

		if(array[col] == WHITE && array[col+1] == WHITE){

			return false;
		}
	}

	return true;
}


int recursive(int row,int col,int array[NUM],int last_group){

	if(row == H){

		if(is_ok(array)){

			return 0;

		}else{

			return -BIG_NUM;
		}
	}

	ll tmp_code = get_code(array);

	auto at = dp[row][col].find(tmp_code);
	if(at != dp[row][col].end()){

		return dp[row][col][tmp_code];
	}

	int next_row,next_col,next_array[2][NUM],next_last_group = last_group;

	//次のrowとcolを設定
	if(col == W-1){

		next_row = row+1;
		next_col = 0;

	}else{

		next_row = row;
		next_col = col+1;
	}

	for(int i = 0; i < 2; i++){
		for(int a = 0; a < W; a++){
			next_array[i][a] = array[a];
		}
	}
	int ret = -BIG_NUM;

	//今回のマスを黒にする
	if(table[row][col] == '#' || table[row][col] == '?'){

		if(col > 0 && next_array[0][col-1] != WHITE && //左が黒
				next_array[0][col] != WHITE && next_array[0][col] != UNDEFINED && //上が黒
				next_array[0][col-1] == next_array[0][col]){ //左と右が同じグループ

			//Do nothing:閉路ができてしまうので黒で塗れない

		}else{

			if(col == 0 || next_array[0][col-1] == WHITE){ //左端、または左が白→左方に黒はない

				switch(next_array[0][col]){
				case UNDEFINED: //左にも上にも黒はない
				case WHITE:
					next_array[0][col] = next_last_group++; //新しいグループを作る
					break;
				default: //上のマスが黒
					//Do nothing:上のマスと同じグループにする
					break;
				}
				ret = max(ret,recursive(next_row,next_col,next_array[0],next_last_group)+1);

			}else{ //col >= 1 && array[col-1] == BLACK

				switch(next_array[0][col]){
				case UNDEFINED:
				case WHITE:
					next_array[0][col] = next_array[0][col-1]; //左のgroupと同じにする
					break;
				default: //上のマスが黒:上のマスと左のマスは異なるグループであるはず

					int new_id = next_array[0][col]; //★今回のマスの番号を新しいIDとして使用★
					int old_id = next_array[0][col-1];

					for(int a = 0; a < W; a++){ //同じIDが飛んで存在する場合あり
						if(next_array[0][a] == old_id){

							next_array[0][a] = new_id;
						}
					}

					break;
				}
				ret = max(ret,recursive(next_row,next_col,next_array[0],next_last_group)+1);

			}
		}
	}

	next_last_group = last_group;

	//今回のマスを白にする
	if(table[row][col] == '.' || table[row][col] == '?'){

		 if(next_array[1][col] == WHITE || (col > 0 && next_array[1][col-1] == WHITE)){ //上か左が白

			  //Do nothing:白が連続するので不可

		 }else{ //上にも左にも白はない

			 if(next_array[1][col] != UNDEFINED){ //上のマスが黒

				int count = 0;

				for(int a = 0; a < W; a++){
					if(next_array[1][a] == array[col]){
						count++;
					}
				}

				if(count == 1){
					//Do nothing:上のマスが孤立するので不可
				}else{

					//上のマスが黒で、左に白がない

					next_array[1][col] = WHITE;
					ret = max(ret,recursive(next_row,next_col,next_array[1],next_last_group));
				}

			 }else{

				 //上のマスがUNDFINEDで、左に白がない

				 next_array[1][col] = WHITE;
				 ret = max(ret,recursive(next_row,next_col,next_array[1],next_last_group));
			 }
		 }
	}

	return dp[row][col][tmp_code] = ret;
}

void dfs(int row,int col,int pre_row,int pre_col){

	if(!FLG)return;

	int next_row,next_col;

	for(int i = 0; i < G[row][col].size(); i++){

		next_row = G[row][col][i].row;
		next_col = G[row][col][i].col;

		if(next_row == pre_row && next_col == pre_col)continue;

		if(check[next_row][next_col]){ //有向に遷移しているので、一度訪れた頂点をまた訪れたら閉路あり

			FLG = false;
			return;
		}
		check[next_row][next_col] = true;

		dfs(next_row,next_col,row,col);
	}
}


int main(){

	scanf("%d %d",&H,&W);

	for(int row = 0; row < H; row++){

		scanf("%s",table[row]);
	}

	//ややこしいので例外処理
	if(H == 1 || W == 1){

		if(H == 1 && W == 1){

			switch(table[0][0]){
			case '.':
				printf("0\n");
				break;
			case '#':
				printf("1\n");
				break;
			case '?':
				printf("1\n");
				break;
			}

			return 0;

		}else if(H == 1){

			//白ますが連続していたら不可
			for(int col = 0; col < W-1; col++){
				if(table[0][col] == '.' && table[0][col+1] == '.'){
					printf("-1\n");
					return 0;
				}
			}

			int ans = 0;

			//とりあえず?のところを前部黒にして、連結しているか調べる
			for(int col = 0; col < W; col++){
				if(table[0][col] == '?'){
					table[0][col] = '#';
					ans++;
				}else if(table[0][col] == '#'){
					ans++;
				}
			}

			for(int i = 0; i < W; i++){

				boss[i] = i;
				height[i] = 0;
			}

			for(int col = 0; col < W-1; col++){
				if(table[0][col] == '#' && table[0][col+1] == '#'){
					unite(col,col+1);
				}
			}

			int num_group = 0;

			for(int col = 0; col < W; col++){
				if(table[0][col] == '#'){
					if(get_boss(col) == col){
						num_group++;
					}
				}
			}

			if(num_group >= 2){

				printf("-1\n");

			}else{

				printf("%d\n",ans);
			}

			return 0;

		}else{ //W == 1


			//白ますが連続していたら不可
			for(int row = 0; row < H-1; row++){
				if(table[row][0] == '.' && table[row+1][0] == '.'){
					printf("-1\n");
					return 0;
				}
			}

			int ans = 0;

			//とりあえず?のところを前部黒にして、連結しているか調べる
			for(int row = 0; row < H; row++){
				if(table[row][0] == '?'){
					table[row][0] = '#';
					ans++;
				}else if(table[row][0] == '#'){
					ans++;
				}
			}

			for(int i = 0; i < H; i++){

				boss[i] = i;
				height[i] = 0;
			}

			for(int row = 0; row < H-1; row++){
				if(table[row][0] == '#' && table[row+1][0] == '#'){
					unite(row,row+1);
				}
			}

			int num_group = 0;

			for(int row = 0; row < H; row++){
				if(table[row][0] == '#'){
					if(get_boss(row) == row){
						num_group++;
					}
				}
			}

			if(num_group >= 2){

				printf("-1\n");

			}else{

				printf("%d\n",ans);
			}
			return 0;
		}
	}

	int adj_row,adj_col;

	//最初から閉路ができてないか調べる(dfsで調べるため、エッジを作る)
	for(int row = 0; row < H; row++){
		for(int col = 0; col < W; col++){
			if(table[row][col] != '#')continue;

			for(int i = 0; i < 4; i++){

				adj_row = row+diff_row[i];
				adj_col = col+diff_col[i];

				if(rangeCheck(adj_row,adj_col) == false || table[adj_row][adj_col] != '#')continue;

				G[row][col].push_back(Info(adj_row,adj_col));
			}
		}
	}

	for(int row = 0; row < H; row++){
		for(int col = 0; col < W; col++){
			if(table[row][col] != '#')continue;

			for(int a = 0; a < H; a++){
				for(int b = 0; b < W; b++){
					check[a][b] = false;
				}
			}

			check[row][col] = true;
			FLG= true;

			dfs(row,col,-1,-1);

			if(!FLG){

				printf("-1\n");
				return 0;
			}
		}
	}

	int first_array[NUM];

	for(int i = 0; i < W; i++){

		first_array[i] = UNDEFINED;
	}

	int ret = recursive(0,0,first_array,2);

	if(ret < 0){

		printf("-1\n");
	}else{

		printf("%d\n",ret);
	}

	return 0;
}
accuracy: 0.19811320754716982
time_ms: 1140
memory_kb: 115700
final_rank: 19

code_snippet: #include<iostream>
#include<string>
#include<algorithm>
#include<vector>
#include<iomanip>
#include<math.h>
#include<complex>
#include<queue>
#include<deque>
#include<stack>
#include<map>
#include<set>
#include<bitset>
#include<functional>
#include<assert.h>
#include<numeric>
using namespace std;
#define REP(i,m,n) for(int i=(int)(m) ; i < (int) (n) ; ++i )
#define rep(i,n) REP(i,0,n)
using ll = long long;
const int inf=1e9+7;
const ll longinf=1LL<<60 ;
const ll mod=1e9+7 ;

struct UnionFind{
   vector<int> par;
   UnionFind(int n):par(n,-1){}
   int find(int x){
       if(par[x]<0)return x;
       return par[x]=find(par[x]);
   }
   bool unite(int x,int y){
       x=find(x);
       y=find(y);
       if(x>y)swap(x,y);
       if(x==y)return false;
       else{
           par[x]+=par[y];
           par[y]=x;
       }
       return true;
   }

   bool same(int x,int y){
       return find(x)==find(y);
   }
   int size(int x){
       return -par[find(x)];
   }
};
int main(){
    int h,w;
    cin>>h>>w;
    string s[h];
    rep(i,h)cin>>s[i];
    map<ll,int> dp[h];
    int all=1<<w;
    rep(i,all){
        int a[w];
        rep(j,w){
            if(s[0][j]=='.')a[j]=0;
            if(s[0][j]=='#')a[j]=1;
            if(s[0][j]=='?')a[j]=(i>>j)&1;
        }
        UnionFind uf(w+1);
        bool ok=true;
        rep(j,w-1){
            if(a[j]&&a[j+1])uf.unite(j,j+1);
            if(!a[j]&&!a[j+1])ok=false;
        }
        if(!ok)continue;
        ll res=0;
        int cnt=0;
        rep(j,w){
            res*=12;
            if(a[j])res+=(uf.find(j)+1),cnt++;
        }
        dp[0][res]=max(dp[0][res],cnt);
    }
    rep(i,h-1){
        rep(mask,all){
            int a[w];
            bool can=true;
            rep(j,w){
                if(s[i+1][j]=='.')a[j]=0;
                if(s[i+1][j]=='#')a[j]=1;
                if(s[i+1][j]=='?')a[j]=(mask>>j)&1;
            }
            rep(j,w-1){
                if(!a[j]&&!a[j+1])can=false;
            }
            if(!can)continue;
            for(auto p : dp[i]){
                int b[w];
                ll cur=p.first;
                rep(j,w){
                    b[w-j-1]=12+cur%12;
                    cur/=12;
                }
                bool ok=true;
                UnionFind uf(26);
                rep(j,w-1){
                    if(a[j]&&a[j+1])uf.unite(j,j+1);
                }
                rep(j,w){
                    if(a[j]&&b[j]>12){
                        if(!uf.unite(j,b[j]))ok=false;
                    }
                    if(!a[j]&&b[j]==12)ok=false;
                }
                if(i!=h-2||w!=1)rep(j,w)if(uf.find(b[j])>12)ok=false;
                if(!ok)continue;
                ll res=0;
                int cnt=p.second;
                rep(j,w){
                    res*=12;
                    if(a[j]){
                        res+=(uf.find(j)+1),cnt++;
                    }
                }
                dp[i+1][res]=max(dp[i+1][res],cnt);
            }
        }
    }
    int ans=-1;
    for(auto p : dp[h-1]){
        ll cur=p.first;
        bool ok=true;
        set<int> st;
        while(cur){
            if(cur%12)st.insert(cur%12);
            cur/=12;
        }
        if(st.size()==1||st.size()==0)ans=max(ans,p.second);
    }

    cout<<ans<<endl;
    
    return 0;
}
accuracy: 1
time_ms: 560
memory_kb: 4444
final_rank: 8

code_snippet: #include<iostream>
#include<string>
#include<algorithm>
#include<vector>
#include<iomanip>
#include<math.h>
#include<complex>
#include<queue>
#include<deque>
#include<stack>
#include<map>
#include<set>
#include<bitset>
#include<functional>
#include<assert.h>
#include<numeric>
using namespace std;
#define REP(i,m,n) for(int i=(int)(m) ; i < (int) (n) ; ++i )
#define rep(i,n) REP(i,0,n)
using ll = long long;
const int inf=1e9+7;
const ll longinf=1LL<<60 ;
const ll mod=1e9+7 ;

struct UnionFind{
   vector<int> par;
   UnionFind(int n):par(n,-1){}
   int find(int x){
       if(par[x]<0)return x;
       return par[x]=find(par[x]);
   }
   bool unite(int x,int y){
       x=find(x);
       y=find(y);
       if(x>y)swap(x,y);
       if(x==y)return false;
       else{
           par[x]+=par[y];
           par[y]=x;
       }
       return true;
   }

   bool same(int x,int y){
       return find(x)==find(y);
   }
   int size(int x){
       return -par[find(x)];
   }
};
int main(){
    int h,w;
    cin>>h>>w;
    string s[h];
    rep(i,h)cin>>s[i];
    map<ll,int> dp[h];
    int all=1<<w;
    rep(i,all){
        int a[w];
        rep(j,w){
            if(s[0][j]=='.')a[j]=0;
            if(s[0][j]=='#')a[j]=1;
            if(s[0][j]=='?')a[j]=(i>>j)&1;
        }
        UnionFind uf(w+1);
        bool ok=true;
        rep(j,w-1){
            if(a[j]&&a[j+1])uf.unite(j,j+1);
            if(!a[j]&&!a[j+1])ok=false;
        }
        if(!ok)continue;
        ll res=0;
        int cnt=0;
        rep(j,w){
            res*=12;
            if(a[j])res+=(uf.find(j)+1),cnt++;
        }
        dp[0][res]=max(dp[0][res],cnt);
    }
    rep(i,h-1){
        rep(mask,all){
            int a[w];
            bool can=true;
            rep(j,w){
                if(s[i+1][j]=='.')a[j]=0;
                if(s[i+1][j]=='#')a[j]=1;
                if(s[i+1][j]=='?')a[j]=(mask>>j)&1;
            }
            rep(j,w-1){
                if(!a[j]&&!a[j+1])can=false;
            }
            if(!can)continue;
            for(auto p : dp[i]){
                int b[w];
                ll cur=p.first;
                rep(j,w){
                    b[w-j-1]=12+cur%12;
                    cur/=12;
                }
                bool ok=true;
                UnionFind uf(26);
                rep(j,w-1){
                    if(a[j]&&a[j+1])uf.unite(j,j+1);
                }
                rep(j,w){
                    if(a[j]&&b[j]>12){
                        if(!uf.unite(j,b[j]))ok=false;
                    }
                    if(!a[j]&&b[j]==12)ok=false;
                }
                if(i!=h-2)rep(j,w)if(uf.find(b[j])>12)ok=false;
                if(!ok)continue;
                ll res=0;
                int cnt=p.second;
                rep(j,w){
                    res*=12;
                    if(a[j]){
                        res+=(uf.find(j)+1),cnt++;
                    }
                }
                dp[i+1][res]=max(dp[i+1][res],cnt);
            }
        }
    }
    int ans=-1;
    for(auto p : dp[h-1])ans=max(ans,p.second);
    cout<<ans<<endl;
    
    return 0;
}
accuracy: 0.4811320754716981
time_ms: 570
memory_kb: 4256
final_rank: 16

code_snippet: #include<bits/stdc++.h>
using namespace std;

class UnionFind{
    vector<int> par;
    vector<int> rank;
    public:
    UnionFind(int n):rank(n),par(n){
        iota(par.begin(),par.end(),0);
    }
    int find(int x){
        if(par[x]==x) return x;
        else return par[x]=find(par[x]);
    }
    void unite(int x,int y){
        x=find(x),y=find(y);
        if(rank[x]<rank[y]) par[x]=y;
        else{
            if(rank[x]==rank[y]) rank[x]++;
            par[y]=x;
        }
    }
    bool isSame(int x,int y){
        return find(x)==find(y);
    }
};
int main(){
    int h,w;
    cin>>h>>w;
    vector<string> c(h);
    for(int i=0;i<h;i++) cin>>c[i];
    
    vector<int> vec;
    for(int bit=0;bit<(1<<w);bit++){
        bool isok=true;
        for(int i=0;i+1<w;i++){
            isok = isok && (((bit>>i)&1) || ((bit>>(i+1))&1));
        }
        if(isok) vec.push_back(bit);
    }
    auto isValid=[&](int bit,int row){
        bool isok=true;
        for(int i=0;i<w;i++){
            if(c[row][i]=='#'){
                isok= isok && ((bit>>i)&1);
            }
            else if(c[row][i]=='.'){
                isok= isok && (!((bit>>i)&1));
            }
        }
        return isok;
    };
    map<vector<int>,int> dp;
    map<vector<int>,int> dpX;
    for(auto bit:vec){
        if(!isValid(bit,0)) continue;
        vector<int> st(w);
        int idx=1;
        for(int i=0;i<w;i++){
            if((bit>>i)&1){
                for(;i<w;i++){
                    if(!((bit>>i)&1)) break;
                    st[i]=idx;
                }
                idx++;
            }
        }

        dp[st]=__builtin_popcount(bit);
    }
    dpX=dp;
    for(int i=1;i<h;i++){
        if(i+1==h) dpX=dp;
        map<vector<int>,int> next;
        for(auto bit:vec){
            if(!isValid(bit,i)) continue;
            for(auto &e:dp){
                vector<int> st=e.first;
                int cnt=e.second;
                bool isok=true;
                int v=*max_element(st.begin(),st.end());
                vector<int> hasChil(v);
                for(int i=0;i<w;i++){
                    isok = isok && !(st[i]==0 && ((bit>>i)&1)==0);
                    if(st[i]!=0){
                        hasChil[st[i]-1]=true;
                    }
                }
                if(accumulate(hasChil.begin(),hasChil.end(),0)!=v) continue;
                UnionFind u(v+w);
                for(int i=0;i<w;i++){
                    if(!((bit>>i)&1)) continue;
                    if(st[i]!=0){
                        if(u.isSame(st[i]-1,v+i)){
                            isok=false;
                            break; 
                        }
                        u.unite(st[i]-1,v+i);
                    }
                    if(((bit>>(i+1))&1)){
                        u.unite(v+i,v+i+1);
                    }
                }
                if(!isok) continue;
                for(int i=0;i<v;i++){
                    for(int j=0;j<=w;j++){
                        if(j==w){
                            isok=false;
                            break;
                        }
                        if(u.isSame(i,v+j)) break;
                    }
                }
                if(!isok) continue;
                int idx=1;
                vector<int> to(w);
                
                for(int i=0;i<w;i++){
                    if(!((bit>>i)&1)) continue;
                    for(int j=0;j<i;j++){
                        if(u.isSame(v+i,v+j)){
                            to[i]=to[j];
                            break;
                        }
                    }
                    if(to[i]==0) to[i]=idx++;
                }
                next[to]=max(next[to],cnt+__builtin_popcount(bit));
            }
        }
        dp=next;
    }
    int res=-1;
    for(int i=0;i<=w;i++){
        if(i==w && w==1){
            for(auto &e:dpX){
                if(*max_element(e.first.begin(),e.first.end())>1) continue;;
                res=max(res,e.second);
            }       
            break;
        }
        if(i==w) break;
        if(c[h-1][i]=='#') break;
    }
    
    for(auto &e:dp){
        if(*max_element(e.first.begin(),e.first.end())>1) continue;;
        res=max(res,e.second);
    }
    cout<<res<<endl;
    return 0;
}
accuracy: 1
time_ms: 770
memory_kb: 4096
final_rank: 11

code_snippet: #include<bits/stdc++.h>
using namespace std;

class UnionFind{
    vector<int> par;
    vector<int> rank;
    public:
    UnionFind(int n):rank(n),par(n){
        iota(par.begin(),par.end(),0);
    }
    int find(int x){
        if(par[x]==x) return x;
        else return par[x]=find(par[x]);
    }
    void unite(int x,int y){
        x=find(x),y=find(y);
        if(rank[x]<rank[y]) par[x]=y;
        else{
            if(rank[x]==rank[y]) rank[x]++;
            par[y]=x;
        }
    }
    bool isSame(int x,int y){
        return find(x)==find(y);
    }
};
int main(){
    int h,w;
    cin>>h>>w;
    vector<string> c(h);
    for(int i=0;i<h;i++) cin>>c[i];
    if(h==2){
        
    }
    vector<int> vec;
    for(int bit=0;bit<(1<<w);bit++){
        bool isok=true;
        for(int i=0;i+1<w;i++){
            isok = isok && (((bit>>i)&1) || ((bit>>(i+1))&1));
        }
        if(isok) vec.push_back(bit);
    }
    auto isValid=[&](int bit,int row){
        bool isok=true;
        for(int i=0;i<w;i++){
            if(c[row][i]=='#'){
                isok= isok && ((bit>>i)&1);
            }
            else if(c[row][i]=='.'){
                isok= isok && (!((bit>>i)&1));
            }
        }
        return isok;
    };
    map<vector<int>,int> dp;
    map<vector<int>,int> dpX;
    for(auto bit:vec){
        if(!isValid(bit,0)) continue;
        vector<int> st(w);
        int idx=1;
        for(int i=0;i<w;i++){
            if((bit>>i)&1){
                for(;i<w;i++){
                    if(!((bit>>i)&1)) break;
                    st[i]=idx;
                }
                idx++;
            }
        }
        dp[st]=__builtin_popcount(bit);
    }
    for(int i=1;i<h;i++){
        if(i+1==h) dpX=dp;
        map<vector<int>,int> next;
        for(auto bit:vec){
            if(!isValid(bit,i)) continue;
            for(auto &e:dp){
                vector<int> st=e.first;
                int cnt=e.second;
                bool isok=true;
                int v=*max_element(st.begin(),st.end());
                vector<int> hasChil(v);
                for(int i=0;i<w;i++){
                    isok = isok && !(st[i]==0 && ((bit>>i)&1)==0);
                    if(st[i]!=0){
                        hasChil[st[i]-1]=true;
                    }
                }
                if(accumulate(hasChil.begin(),hasChil.end(),0)!=v) continue;
                UnionFind u(v+w);
                for(int i=0;i<w;i++){
                    if(!((bit>>i)&1)) continue;
                    if(st[i]!=0){
                        if(u.isSame(st[i]-1,v+i)){
                            isok=false;
                            break; 
                        }
                        u.unite(st[i]-1,v+i);
                    }
                    if(((bit>>(i+1))&1)){
                        u.unite(v+i,v+i+1);
                    }
                }
                if(!isok) continue;
                for(int i=0;i<v;i++){
                    for(int j=0;j<=w;j++){
                        if(j==w){
                            isok=false;
                            break;
                        }
                        if(u.isSame(i,v+j)) break;
                    }
                }
                if(!isok) continue;
                int idx=1;
                vector<int> to(w);
                
                for(int i=0;i<w;i++){
                    if(!((bit>>i)&1)) continue;
                    for(int j=0;j<i;j++){
                        if(u.isSame(v+i,v+j)){
                            to[i]=to[j];
                            break;
                        }
                    }
                    if(to[i]==0) to[i]=idx++;
                }
                next[to]=max(next[to],cnt+__builtin_popcount(bit));
            }
        }
        dp=next;
    }
    int res=-1;
    for(int i=0;i<=w;i++){
        if(i==w && w==1){
            for(auto &e:dpX){
                if(*max_element(e.first.begin(),e.first.end())!=1) continue;;
                res=max(res,e.second);
            }       
            break;
        }
        if(c[h-1][i]=='#') break;
    }
    
    for(auto &e:dp){
        if(*max_element(e.first.begin(),e.first.end())!=1) continue;;
        res=max(res,e.second);
    }
    cout<<res<<endl;
    return 0;
}
accuracy: 0.6132075471698113
time_ms: 790
memory_kb: 4080
final_rank: 14

code_snippet: #include <cstdio>
#include <algorithm>
#include <cstring>
#include <map>
using namespace std;

int H, W;
char board[15][15];
using Board = map<string, map<int, int> >;
void chmax(int &A, int B) { A = max(A, B); }

string get_uni(string s, int x, int mode) {
    vector<int> v(10), checked(10); iota(v.begin(), v.end(), 0);
    if(mode == 1) {
        if(x != 0 && isdigit(s[x]) && isdigit(s[x-1])) {
            int a = s[x] - '0', b = s[x-1] - '0';
            v[a] = b;
        }
        else {
            bool exist_num = false;
            if(x != 0 && isdigit(s[x-1])) {
                exist_num = true;
                s[x] = s[x-1];
            }
            if(isdigit(s[x])) {
                exist_num = true;
            }

            if(!exist_num) {
                s[x] = '8';
            }
        }
    }

    string ret = "";
    int id = 0;
    for(int i=0; i<W; i++) {
        if(isdigit(s[i])) {
            int val = v[ s[i] - '0' ];
            if(!checked[val]) checked[val] = ++id;
            ret += (char)('0' + checked[val]);
        }
        else {
            ret += s[i];
        }
    }
    return ret;
}

bool valid(string s) {
    int pre = -1;
    for(auto c : s) {
        if(isdigit(c)) {
            if(pre == -1) pre = c - '0';
            else if(pre != c - '0') return false;
        }
    }
    return true;
}

string to_bin(int N) {
    string ret = "";
    for(int i=0; i<W; i++, N>>=1) {
        int c = (N & 1);
        ret += (char)('0' + c);
    }
    return ret;
}

int main() {
    scanf("%d%d", &H, &W);
    for(int i=0; i<H; i++) {
        for(int j=0; j<W; j++) {
            scanf(" %c", &board[i][j]);
        }
    }

    string emp_str(W, '.');
    Board cur, nxt;
    cur[emp_str][0] = 0;

    for(int pos=0; pos<H*W; pos++) {
        int row = pos / W, col = pos % W;
        char c = board[row][col];
        for(auto x : cur) {
            string uni = x.first;
            for(auto y : cur[uni]) {
                int bit = y.first, pre = y.second;
                int base = bit - ((bit >> col & 1) << col);

                // paint (black)
                if(c == '#' || c == '?') {
                    if(col == 0 || (uni[col] != uni[col-1] || !isdigit(uni[col]))) {
                        string tmp = uni;

                        tmp = get_uni(tmp, col, 1);                    
                        int nbit = base | (1 << col);
                        chmax(nxt[tmp][nbit], pre + 1);
                    }
                }

                // paint (white)
                if(c == '.' || c == '?') {
                    bool ok = true;
                    if(row != 0 && !(bit >>  col      & 1)) ok = false;
                    if(col != 0 && !(bit >> (col - 1) & 1)) ok = false;

                    char target = uni[col];
                    int cnt = 0;
                    for(int i=0; i<W; i++) cnt += (uni[i] == target);
                    if(isdigit(target) && cnt == 1 && W != 1) ok = false;

                    if(ok) {
                        string tmp = uni;
                        tmp[col] = '.';
                        tmp = get_uni(tmp, col, 0);

                        int nbit = base;
                        chmax(nxt[tmp][nbit], pre);
                    }
                }
            }
        }
        cur.clear();
        swap(cur, nxt);
    }

    int ans = -1;
    for(auto x : cur) {
        string uni = x.first;
        if(!valid(uni)) continue;
        
        for(auto y : cur[uni]) {
            int val = y.second;
            chmax(ans, val);
        }
    }
    printf("%d\n", ans);
    return 0;
}
accuracy: 1
time_ms: 250
memory_kb: 4188
final_rank: 2

code_snippet: #include <cstdio>
#include <algorithm>
#include <cstring>
#include <map>
using namespace std;

int H, W;
char board[15][15];
using Board = map<string, map<int, int> >;
void chmax(int &A, int B) { A = max(A, B); }

string get_uni(string s, int x, int mode) {
    vector<int> v(10), checked(10); iota(v.begin(), v.end(), 0);
    if(mode == 1) {
        if(x != 0 && isdigit(s[x]) && isdigit(s[x-1])) {
            int a = s[x] - '0', b = s[x-1] - '0';
            v[a] = b;
        }
        else {
            bool exist_num = false;
            if(x != 0 && isdigit(s[x-1])) {
                exist_num = true;
                s[x] = s[x-1];
            }
            if(isdigit(s[x])) {
                exist_num = true;
            }

            if(!exist_num) {
                s[x] = '8';
            }
        }
    }

    string ret = "";
    int id = 0;
    for(int i=0; i<W; i++) {
        if(isdigit(s[i])) {
            int val = v[ s[i] - '0' ];
            if(!checked[val]) checked[val] = ++id;
            ret += (char)('0' + checked[val]);
        }
        else {
            ret += s[i];
        }
    }
    return ret;
}

bool valid(string s) {
    int pre = -1;
    for(auto c : s) {
        if(isdigit(c)) {
            if(pre == -1) pre = c - '0';
            else if(pre != c - '0') return false;
        }
    }
    return true;
}

string to_bin(int N) {
    string ret = "";
    for(int i=0; i<W; i++, N>>=1) {
        int c = (N & 1);
        ret += (char)('0' + c);
    }
    return ret;
}

int main() {
    scanf("%d%d", &H, &W);
    for(int i=0; i<H; i++) {
        for(int j=0; j<W; j++) {
            scanf(" %c", &board[i][j]);
        }
    }

    string emp_str(W, '.');
    Board cur, nxt;
    cur[emp_str][0] = 0;

    for(int pos=0; pos<H*W; pos++) {
        int row = pos / W, col = pos % W;
        char c = board[row][col];
        for(auto x : cur) {
            string uni = x.first;
            for(auto y : cur[uni]) {
                int bit = y.first, pre = y.second;
                // printf("row = %d, col = %d, dp[%s][%s] = %d\n", row+1, col+1, uni.c_str(), to_bin(bit).c_str(), pre);

                int base = bit - ((bit >> col & 1) << col);

                // paint (black)
                if(c == '#' || c == '?') {
                    // printf("cond 1: row = %d, col = %d\n", row+1, col+1);
                    if(col == 0 || (uni[col] != uni[col-1] || !isdigit(uni[col]))) {
                        string tmp = uni;

                        // printf("tmp = %s, ", tmp.c_str());
                        tmp = get_uni(tmp, col, 1);
                        // printf("nxt = %s\n", tmp.c_str());
                    
                        int nbit = base | (1 << col);
                        chmax(nxt[tmp][nbit], pre + 1);
                    }
                }

                // paint (white)
                if(c == '.' || c == '?') {
                    // printf("cond 2: row = %d, col = %d\n", row+1, col+1);

                    bool ok = true;
                    if(row != 0 && !(bit >>  col      & 1)) ok = false;
                    if(col != 0 && !(bit >> (col - 1) & 1)) ok = false;

                    char target = uni[col];
                    int cnt = 0;
                    for(int i=0; i<W; i++) cnt += (uni[i] == target);
                    if(isdigit(target) && cnt == 1 && W != 1) ok = false;

                    if(ok) {
                        string tmp = uni;
                        tmp[col] = '.';
                        tmp = get_uni(tmp, col, 0);

                        int nbit = base;
                        chmax(nxt[tmp][nbit], pre);
                    }
                }
            }
        }
        cur.clear();
        swap(cur, nxt);
    }

    int ans = -1;
    for(auto x : cur) {
        string uni = x.first;
        if(!valid(uni)) continue;
        
        for(auto y : cur[uni]) {
            int val = y.second;
            chmax(ans, val);
        }
    }
    printf("%d\n", ans);
    return 0;
}
accuracy: 1
time_ms: 250
memory_kb: 4200
final_rank: 3

code_snippet: #include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;

int H, W;
char board[15][15];
int dp[2][180000][51];

void chmax(int  &A, int B) {
    A = max(A, B);
}

int B;
int merge(int A, int i) {
    while(A >= B) A -= B;
    
    int b = A % 3;
    A = A - (A % 3);
    if(b == 1 && i != 0) {
        b = i = 2;
    }
    A = (A + b) * 3 + i;
    return A;
}
int get_head(int A) {
    return A / B;
}
int get_tail(int A) {
    return A % 3;
}
void thr_eval(int val, int &cnt_black, int &cnt_white, int &cnt_adj_b) {
    if(val == 0) {
        cnt_white++;
    }
    if(val == 1) {
        cnt_black++;
    }
    if(val == 2) {
        cnt_black++;
        cnt_adj_b++;
    }
}

int main() {
    scanf("%d%d", &H, &W);
    for(int i=0; i<H; i++) {
        for(int j=0; j<W; j++) {
            scanf(" %c", &board[i][j]);
        }
    }

    int P = H*W, Q = 50;
    B = 1;
    for(int i=0; i<W-1; i++) B *= 3;

    memset(dp, -1, sizeof(dp));
    dp[0][0][0] = 0;
    for(int pos=0; pos<P; pos++) {
        int row = pos / W, col = pos % W;
        int cur = pos % 2, nxt = 1 - cur;
        for(int bit=0; bit<(3*B); bit++) {
            for(int diff=0; diff<Q; diff++) {
                if(dp[cur][bit][diff] < 0) continue;

                int val = dp[cur][bit][diff];

                int cnt_black = 0, cnt_white = 0, cnt_adj_b = 0;
                // 真上
                if(row != 0) {
                    int val = get_head(bit);
                    thr_eval(val, cnt_black, cnt_white, cnt_adj_b);
                }
                // 左隣
                if(col != 0) {
                    int val = get_tail(bit);
                    thr_eval(val, cnt_black, cnt_white, cnt_adj_b);
                }

                char c = board[row][col];
                if(c == '#' || c == '?') {
                    int n_diff = diff + 1 - cnt_black;
                    int n_self = (cnt_black ? 2 : 1);
                    if(n_diff > 0) {
                        int nbit = merge(bit, n_self);
                        chmax(dp[nxt][nbit][n_diff], val + 1);
                        // printf("dp[%d][%d][%d] = %d\n", nxt, nbit, n_diff, val + 1);
                    }
                }
                if(c == '.' || c == '?') {
                    if(row != 0) {
                        if(get_head(bit) == 1 && val != 1) continue;
                    }
                    if(row == H-1 && col != 0) {
                        if(get_tail(bit) == 1 && val != 1) continue;
                    }

                    if(cnt_white == 0) {
                        int nbit = merge(bit, 0);
                        chmax(dp[nxt][nbit][diff], val);
                        // printf("dp[%d][%d][%d] = %d\n", nxt, nbit, diff, val);
                    }
                }

                dp[cur][bit][diff] = -1;
            }
        }
    }

    int ans = -1;
    for(int bit=0; bit<3*B; bit++) {
        if(dp[P%2][bit][1] < 0) continue;
        chmax(ans, dp[P%2][bit][1]);
    }
    printf("%d\n", ans);
    return 0;
}
accuracy: 0.2169811320754717
time_ms: 680
memory_kb: 74476
final_rank: 17

code_snippet: #include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;

int H, W;
char board[15][15];
int dp[2][180000][51];

void chmax(int  &A, int B) {
    A = max(A, B);
}

int B;
int merge(int A, int i) {
    while(A >= B) A -= B;
    
    int b = A % 3;
    A = A - (A % 3);
    if(b == 1 && i != 0) {
        b = i = 2;
    }
    A = (A + b) * 3 + i;
    return A;
}
int get_head(int A) {
    return A / B;
}
int get_tail(int A) {
    return A % 3;
}
void thr_eval(int val, int &cnt_black, int &cnt_white, int &cnt_adj_b) {
    if(val == 0) {
        cnt_white++;
    }
    if(val == 1) {
        cnt_black++;
    }
    if(val == 2) {
        cnt_black++;
        cnt_adj_b++;
    }
}

int main() {
    scanf("%d%d", &H, &W);
    for(int i=0; i<H; i++) {
        for(int j=0; j<W; j++) {
            scanf(" %c", &board[i][j]);
        }
    }

    int P = H*W, Q = 50;
    B = 1;
    for(int i=0; i<W-1; i++) B *= 3;

    memset(dp, -1, sizeof(dp));
    dp[0][0][0] = 0;
    for(int pos=0; pos<P; pos++) {
        int row = pos / W, col = pos % W;
        int cur = pos % 2, nxt = 1 - cur;
        for(int bit=0; bit<(3*B); bit++) {
            for(int diff=0; diff<Q; diff++) {
                if(dp[cur][bit][diff] < 0) continue;

                int val = dp[cur][bit][diff];

                int cnt_black = 0, cnt_white = 0, cnt_adj_b = 0;
                // 真上
                if(row != 0) {
                    int val = get_head(bit);
                    thr_eval(val, cnt_black, cnt_white, cnt_adj_b);
                }
                // 左隣
                if(col != 0) {
                    int val = get_tail(bit);
                    thr_eval(val, cnt_black, cnt_white, cnt_adj_b);
                }

                char c = board[row][col];
                if(c == '#' || c == '?') {
                    int n_diff = diff + 1 - cnt_black;
                    int n_self = (cnt_black ? 2 : 1);
                    if(n_diff > 0) {
                        int nbit = merge(bit, n_self);
                        chmax(dp[nxt][nbit][n_diff], val + 1);
                    }
                }
                if(c == '.' || c == '?') {
                    if(row != 0) {
                        if(get_head(bit) == 1) continue;
                    }
                    if(row == H-1 && col != 0) {
                        if(get_tail(bit) == 1) continue;
                    }

                    if(cnt_white == 0) {
                        int nbit = merge(bit, 0);
                        chmax(dp[nxt][nbit][diff], val);
                    }
                }

                dp[cur][bit][diff] = -1;
            }
        }
    }

    int ans = -1;
    for(int bit=0; bit<3*B; bit++) {
        if(dp[P%2][bit][1] < 0) continue;
        chmax(ans, dp[P%2][bit][1]);
    }
    printf("%d\n", ans);
    return 0;
}
accuracy: 0.05660377358490566
time_ms: 20
memory_kb: 74476
final_rank: 20