Problem:
〜魔女からこの世界を守るため
キュゥべえ
と共に戦う 5 人の魔法少女達の物語〜
問題 A
問題文
薔薇園の魔女 GERTRUD は幅
W
メートル，高さ
H
メートルの長方形の庭でバラを育てている．庭は一辺
1
メートルの正方形で区切られており，
W\times H
のブロックに分けられている．各ブロックはバラが育てられているか育てられていないかのどちらかである．
ただ驚くべきことに，この庭で育てられているバラはブロックを越えて絡み合い
1
つの生命体となっている．この生命体は辺を共有しているブロック間を越えて絡み合うことができ，どこかある
1
点を共有していれば同じ生命体となる．
巴マミ
は庭の左下の角から直線に必殺技「ティロ・フィナーレ」で巨大な銃を撃ち，その弾丸が通る直線上でその生命体を分割した時，生命体が出来る限り多くの分割数に分断されるようにすることによりダメージを与えたい．ティロ・フィナーレは最大でこの生物を何分割できるか求めよ．
入力形式
入力は以下の形式で与えられる．
H\ W\\
f_{11} f_{12} ... f_{1W}\\
f_{21} f_{22} ... f_{2W}\\
...\\
f_{H1} f_{H2} ... f_{HW}\\
H
は庭の高さ，
W
は庭の幅を表す．
f_{ij}
は庭の各ブロックを表す文字であり，上から
i
行目，左から
j
列目のブロックの状態を表す．ブロックにバラが育てられている場合は
f_{ij}
は
'#'
となり，そうでない場合は
'.'
となる．
出力形式
生命体を直線で分割する時に，最大でいくつの部分に分割できるかを1行で出力せよ．
制約
1 ≤ H ≤ 600
1 ≤ W ≤ 600
f_{ij}
は
'#'
,
'.'
のいずれかである．
少なくとも
1
つは
f_{ij} =
'#'
となるマス
f_{ij}
が存在する．
2
つのブロックが辺を共有するとき，それらは
隣接している
と呼ぶことにする．任意の
2
つの異なる
'#'
のブロック
f_A, f_B
に対して，
f_A
から隣接している
'#'
のブロックを辿っていって
f_B
に着くことができる．(すなわち，薔薇のブロックは連結である．)
入力中で
1
行目の行，
H
行目の行，
1
列目の列，または
W
列目の列にあるブロックを
盤面の端のブロック
と呼ぶことにする．任意の
'.'
のブロック
f_C
に対して，
f_C
から隣接している
'.'
のブロックを辿っていって，ある
'.'
の盤面の端のブロックに着くことができる．(すなわち，入力に"空洞"のブロックは存在しない．)
入出力例
入力例 1
3 5
##..#
#..##
####.
出力例1
4
このとき以下のように
4
つの部分に分割することができる．
入力例 2
3 3
#.#
###
#.#
出力例 2
3
入力例 3
10 9
.........
.........
####.....
#..#.##..
#..#..#..
#..##.###
#..##...#
##..##.##
###.#..#.
###.####.
出力例 3
6
入力例 4
10 11
###########
#.#.#.#.#.#
#.#.#.#.#.#
#.#.#.#.#.#
#.#.#.#.#.#
#.#.#.#.#.#
#.#.#.#.#.#
#.#.#.#.#.#
#.#.#.#.#.#
#.#.#.#.#.#
出力例 4
7
入力例 5
25 38
...........#...............#..........
...........###..........####..........
...........#####.......####...........
............###############...........
............###############...........
............##############............
.............#############............
............###############...........
...........#################..........
.......#...#################...#......
.......##.##################..##......
........####################.##.......
..........####################........
.........#####..########..#####.......
.......######....#####....######......
......########...#####..########.#....
....#######..#...#####..#..########...
..#########.....#######......#######..
...#######......#######........###....
..####.........#########........###...
...............#########..............
..............##########..............
..............##########..............
...............########...............
...............########...............
出力例 5
8
Problem Setter: Flat35

Submitted solutions:

code_snippet: #include "bits/stdc++.h"
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
const int INF = 1e9;
const ll LINF = 1e18;
template<class S,class T> ostream& operator << (ostream& out,const pair<S,T>& o){ out << "(" << o.first << "," << o.second << ")"; return out; }
template<class T> ostream& operator << (ostream& out,const vector<T> V){ for(int i = 0; i < V.size(); i++){ out << V[i]; if(i!=V.size()-1) out << " ";} return out; }
template<class T> ostream& operator << (ostream& out,const vector<vector<T> > Mat){ for(int i = 0; i < Mat.size(); i++) { if(i != 0) out << endl; out << Mat[i];} return out; }
template<class S,class T> ostream& operator << (ostream& out,const map<S,T> mp){ out << "{ "; for(auto it = mp.begin(); it != mp.end(); it++){ out << it->first << ":" << it->second; if(mp.size()-1 != distance(mp.begin(),it)) out << ", "; } out << " }"; return out; }

/*
 <url:>
 問題文============================================================
 =================================================================
 解説=============================================================
 ================================================================
 */

const double eps = 1e-9;
ll solve(){
    ll H,W; cin >> H >> W;
    ll res = 1;
    vector<vector<char>> masu(H+2,vector<char>(W+2,'.'));
    vector<pair<double,int>> event;
    for(int i = 1; i <= H;i++){
        for(int j = 1; j <= W;j++){
            cin >> masu[i][j];
        }
    }
    
    vector<vector<pii>> masu2(H+2,vector<pii>(W+2));
    for(int i = 1; i <= H;i++){
        for(int j = 1; j <= W;j++){
            masu2[i][j] = {j-1,H-i};
        }
    }
    //cout << masu << endl;
    //cout << masu2 << endl;
    for(int i = 1; i <= H;i++){
        for(int j = 1; j <= W;j++){
            if(masu[i][j] == '#'){
                
                double angle = 0;
                // increment pattern
                //  ..
                //  .#
                if(masu[i-1][j-1] == '.' && masu[i-1][j] == '.' && masu[i][j-1] == '.'){
                    angle = atan2(masu2[i][j].second+1,masu2[i][j].first);
                    event.push_back({angle,-1});
                }
                
                // increment pattern
                //  ##
                //  #.
                if(masu[i+1][j+1] == '.' && masu[i+1][j] == '#' && masu[i][j+1] == '#'){
                    angle = atan2(masu2[i][j].second,masu2[i][j].first+1);
                    event.push_back({angle,-1});
                }
                
                // decrement pattern
                //  .#
                //  ##
                if(masu[i-1][j-1] == '.' && masu[i-1][j] == '#' && masu[i][j-1] == '#'){
                    angle = atan2(masu2[i][j].second+1,masu2[i][j].first);
                    event.push_back({angle,1});
                }
                
                // decrement pattern
                //  #.
                //  ..
                if(masu[i+1][j+1] == '.' && masu[i+1][j] == '.' && masu[i][j+1] == '.'){
                    angle = atan2(masu2[i][j].second,masu2[i][j].first+1);
                    event.push_back({angle,1});
                }
            }
        }
    }
    
    sort(event.begin(),event.end());
    
    ll cnt = 1;
    for(auto it = event.rbegin(); it != event.rend(); it++){
        auto e = *it;
        //cout << -e.second << endl;
        cnt -= e.second;
        res = max(res,cnt);
    }
    return res;
}
int main(void) {
    cin.tie(0); ios_base::sync_with_stdio(false);
    cout << solve() << endl;
    return 0;
}
accuracy: 1
time_ms: 10
memory_kb: 8728
final_rank: 13

code_snippet: #include <iostream>
#include <iomanip>
#include <cassert>
#include <vector>
#include <algorithm>
#include <utility>
#include <numeric>
#include <tuple>
// #include "Src/Number/IntegerDivision.hpp"
// #include "Src/Utility/BinarySearch.hpp"
// #include "Src/Sequence/CompressedSequence.hpp"
// #include "Src/Sequence/RunLengthEncoding.hpp"
// #include "Src/Algebra/Group/AdditiveGroup.hpp"
// #include "Src/DataStructure/FenwickTree/FenwickTree.hpp"
// using namespace zawa;
// #include "atcoder/modint"
// using mint = atcoder::modint998244353;
int H, W;
std::string S[610];
bool in(int x, int y) {
    return 0 <= x and x < H and 0 <= y and y < W;
}
bool block(int x, int y) {
    return in(x, y) and S[x][y] == '#';
}
bool blank(int x, int y) {
    return !block(x, y);
}
using item = std::pair<std::pair<int, int>, int>;
int norm(std::pair<int, int> p) {
    return p.first * p.first + p.second * p.second;
}
int cross(std::pair<int, int> l, std::pair<int, int> r) {
    return l.first * r.second - l.second * r.first;     
}
bool argcomp(std::pair<int, int> l, std::pair<int, int> r) {
    const int c = cross(l, r);
    if (c) return c > 0;
    else return norm(l) < norm(r);
}
bool comp(item l, item r) {
    return argcomp(l.first, r.first);
}
int main() {
    std::cin.tie(nullptr);
    std::cout.tie(nullptr);
    std::ios::sync_with_stdio(false);
    std::cin >> H >> W;
    for (int i = 0 ; i < H ; i++) {
        std::cin >> S[i];
    }
    std::vector<item> P;
    for (int x = H - 1 ; x >= 0 ; x--) for (int y = 0 ; y < W ; y++) if (block(x, y)) {
        if (blank(x+1,y) and blank(x+1,y+1) and blank(x,y+1)) {
            P.push_back(std::make_pair(
                        // std::make_pair(H-(x+1),y+1),1
                        std::make_pair(y+1,H-(x+1)),1
                        ));
        }
        if (blank(x-1,y) and blank(x-1,y-1) and blank(x,y-1)) {
            P.push_back(std::make_pair(
                        // std::make_pair(H-x,y),-1
                        std::make_pair(y,H-x),-1
                        ));
        }
        if (blank(x-1,y) and blank(x-1,y+1) and blank(x,y+1)) {
            P.push_back(std::make_pair(
                        // std::make_pair(H-x,y+1),0
                        std::make_pair(y+1,H-x),0
                        ));
        }
        if (blank(x+1,y) and blank(x+1,y-1) and blank(x,y-1)) {
            P.push_back(std::make_pair(
                        // std::make_pair(H-(x+1),y),0
                        std::make_pair(y,H-(x+1)),0
                        ));
        }
        if (block(x-1,y) and blank(x-1,y+1) and block(x,y+1)) {
            P.push_back(std::make_pair(
                            std::make_pair(y+1,H-x),0
                        ));
        }
        if (block(x-1,y) and blank(x-1,y-1) and block(x,y-1)) {
            P.push_back(std::make_pair(
                            std::make_pair(y,H-x),1
                        ));
        }
        if (block(x+1,y) and blank(x+1,y+1) and block(x,y+1)) {
            P.push_back(std::make_pair(
                            std::make_pair(y+1,H-x-1),-1
                        ));
        }
        if (block(x+1,y) and blank(x+1,y-1) and block(x,y-1)) {
            P.push_back(std::make_pair(
                            std::make_pair(y+1,H-x-1),0
                        ));
        }
    }
    std::sort(P.begin(), P.end(), comp);
    // for (int k = 0 ; k < (int)P.size() ; k++) std::cout << P[k].first.first << ',' << P[k].first.second << " : " << P[k].second << '\n';
    // std::cout.flush();
    int ans = 1, res = 1;
    for (int i = P[0].first == std::make_pair(0, 0), j = i ; i < (int)P.size() ; i = j) {
        while (j < (int)P.size() and cross(P[i].first, P[j].first) == 0) ans += P[j++].second;
        // for (int k = i ; k < j ; k++) std::cout << P[k].first.first << ',' << P[k].first.second << " : " << P[k].second << '\n';
        // std::cout << "----------------" << std::endl;
        res = std::max(res, ans);
    }
    std::cout << res << '\n';
}
accuracy: 1
time_ms: 10
memory_kb: 8048
final_rank: 10

code_snippet: #include <bits/stdc++.h>
using namespace std;
#define all(v) (v).begin(),(v).end()
#define pb(a) push_back(a)
#define rep(i, n) for(int i=0;i<n;i++)
#define foa(e, v) for(auto&& e : v)
using ll = long long;
const ll MOD7 = 1000000007, MOD998 = 998244353, INF = (1LL << 60);
#define dout(a) cout<<fixed<<setprecision(10)<<a<<endl;

struct node {
    int x, y, val;
};
int cross(int x1, int y1, int x2, int y2) {
    return x1 * y2 - x2 * y1;
}

int main() {
    cin.tie(0);
    ios::sync_with_stdio(false);
    int h, w;
    cin >> h >> w;
    vector<string> s(h);
    rep(i, h) cin >> s[i];
    reverse(all(s));
    vector<node> v;
    rep(i, h) rep(j, w) {
        if(s[i][j] == '#') {
            if(i == h - 1 or s[i + 1][j] == '.') {
                v.push_back(node{j + 1, i + 1, 1});
                v.push_back(node{j, i + 1, -1});
            } 
            if(j == w - 1 or s[i][j + 1] == '.') {
                v.push_back(node{j + 1, i, 1});
                v.push_back(node{j + 1, i + 1, -1});
            }
        }
    } 
    sort(all(v), [&](node a, node b) {
        return cross(a.x, a.y, b.x, b.y) > 0;
    });
    int ans = 0, sum = 0;
    int sz = v.size();
    rep(i, sz) {
        sum += v[i].val;
        while(i + 1 < sz and cross(v[i].x, v[i].y, v[i + 1].x, v[i + 1].y) == 0) {
            i ++;
            sum += v[i].val;
        }
        ans = max(ans, sum);
    }
    cout << ans + 1 << endl;
    
    return 0;
}
accuracy: 1
time_ms: 20
memory_kb: 10336
final_rank: 16

code_snippet: #include <bits/stdc++.h>

using namespace std;

int main() {
    int h, w;
    cin >> h >> w;
    vector<string> v(h);
    for (auto &i : v)
        cin >> i;
    reverse(v.begin(), v.end());
    v.push_back(string(w, '.'));
    for (auto &i : v)
        i += '.';
    map<long double, int> x;
    for (int i = 0; i <= h; i++) {
        for (int j = 0; j <= w; j++) {
            if (i && v[i - 1][j] != v[i][j]) {
                x[(long double) i / (j + 1)]++;
                x[(long double) i / j]--;
            }
            if (j && v[i][j] != v[i][j - 1]) {
                x[(long double) (i + 1) / j]--;
                x[(long double) i / j]++;
            }
        }
    }
    int cnt = 0;
    if (v[0][0] == '#')
        cnt = 1;
    int ans = cnt;
    for (auto [_, t] : x) {
        cnt += t;
        ans = max(ans, cnt);
    }
    cout << ans / 2 + 1 << '\n';
}
accuracy: 1
time_ms: 110
memory_kb: 21032
final_rank: 18

code_snippet: #include <bits/stdc++.h>

using namespace std;

#define rep(i, a, b) for (int i = (int)(a); i < (int)(b); i++)
#define rrep(i, a, b) for (int i = (int)(b)-1; i >= (int)(a); i--)
#define ALL(v) (v).begin(), (v).end()
#define UNIQUE(v) sort(ALL(v)), (v).erase(unique(ALL(v)), (v).end())
#define SZ(v) (int)v.size()
#define MIN(v) *min_element(ALL(v))
#define MAX(v) *max_element(ALL(v))
#define LB(v, x) int(lower_bound(ALL(v), (x)) - (v).begin())
#define UB(v, x) int(upper_bound(ALL(v), (x)) - (v).begin())

using uint = unsigned int;
using ll = long long int;
using ull = unsigned long long;
using i128 = __int128_t;
using u128 = __uint128_t;
const int inf = 0x3fffffff;
const ll INF = 0x1fffffffffffffff;

template <typename T> inline bool chmax(T &a, T b) {
    if (a < b) {
        a = b;
        return 1;
    }
    return 0;
}
template <typename T> inline bool chmin(T &a, T b) {
    if (a > b) {
        a = b;
        return 1;
    }
    return 0;
}
template <typename T, typename U> T ceil(T x, U y) {
    assert(y != 0);
    if (y < 0)
        x = -x, y = -y;
    return (x > 0 ? (x + y - 1) / y : x / y);
}
template <typename T, typename U> T floor(T x, U y) {
    assert(y != 0);
    if (y < 0)
        x = -x, y = -y;
    return (x > 0 ? x / y : (x - y + 1) / y);
}
template <typename T> int popcnt(T x) {
    return __builtin_popcountll(x);
}
template <typename T> int topbit(T x) {
    return (x == 0 ? -1 : 63 - __builtin_clzll(x));
}
template <typename T> int lowbit(T x) {
    return (x == 0 ? -1 : __builtin_ctzll(x));
}

template <class T, class U>
ostream &operator<<(ostream &os, const pair<T, U> &p) {
    os << "P(" << p.first << ", " << p.second << ")";
    return os;
}
template <typename T> ostream &operator<<(ostream &os, const vector<T> &vec) {
    os << "{";
    for (int i = 0; i < vec.size(); i++) {
        os << vec[i] << (i + 1 == vec.size() ? "" : ", ");
    }
    os << "}";
    return os;
}
template <typename T, typename U>
ostream &operator<<(ostream &os, const map<T, U> &map_var) {
    os << "{";
    for (auto itr = map_var.begin(); itr != map_var.end(); itr++) {
        os << "(" << itr->first << ", " << itr->second << ")";
        itr++;
        if (itr != map_var.end())
            os << ", ";
        itr--;
    }
    os << "}";
    return os;
}
template <typename T> ostream &operator<<(ostream &os, const set<T> &set_var) {
    os << "{";
    for (auto itr = set_var.begin(); itr != set_var.end(); itr++) {
        os << *itr;
        ++itr;
        if (itr != set_var.end())
            os << ", ";
        itr--;
    }
    os << "}";
    return os;
}
#ifdef LOCAL
#define show(...) _show(0, #__VA_ARGS__, __VA_ARGS__)
#else
#define show(...) true
#endif
template <typename T> void _show(int i, T name) {
    cerr << '\n';
}
template <typename T1, typename T2, typename... T3>
void _show(int i, const T1 &a, const T2 &b, const T3 &...c) {
    for (; a[i] != ',' && a[i] != '\0'; i++)
        cerr << a[i];
    cerr << ":" << b << " ";
    _show(i + 1, a, c...);
}

#include <unistd.h>

namespace fastio {
static constexpr uint32_t SZ = 1 << 17;
char ibuf[SZ];
char obuf[SZ];
char out[100];
// pointer of ibuf, obuf


uint32_t pil = 0, pir = 0, por = 0;

struct Pre {
    char num[10000][4];
    constexpr Pre() : num() {
        for (int i = 0; i < 10000; i++) {
            int n = i;
            for (int j = 3; j >= 0; j--) {
                num[i][j] = n % 10 | '0';
                n /= 10;
            }
        }
    }
} constexpr pre;

inline void load() {
    memmove(ibuf, ibuf + pil, pir - pil);
    pir = pir - pil + fread(ibuf + pir - pil, 1, SZ - pir + pil, stdin);
    pil = 0;
    if (pir < SZ)
        ibuf[pir++] = '\n';
}

inline void flush() {
    fwrite(obuf, 1, por, stdout);
    por = 0;
}

void rd(char &c) {
    do {
        if (pil + 1 > pir)
            load();
        c = ibuf[pil++];
    } while (isspace(c));
}

void rd(string &x) {
    x.clear();
    char c;
    do {
        if (pil + 1 > pir)
            load();
        c = ibuf[pil++];
    } while (isspace(c));
    do {
        x += c;
        if (pil == pir)
            load();
        c = ibuf[pil++];
    } while (!isspace(c));
}

template <typename T> void rd_real(T &x) {
    string s;
    rd(s);
    x = stod(s);
}

template <typename T> void rd_integer(T &x) {
    if (pil + 100 > pir)
        load();
    char c;
    do
        c = ibuf[pil++];
    while (c < '-');
    bool minus = 0;
    if constexpr (is_signed<T>::value || is_same_v<T, i128>) {
        if (c == '-') {
            minus = 1, c = ibuf[pil++];
        }
    }
    x = 0;
    while ('0' <= c) {
        x = x * 10 + (c & 15), c = ibuf[pil++];
    }
    if constexpr (is_signed<T>::value || is_same_v<T, i128>) {
        if (minus)
            x = -x;
    }
}

void rd(int &x) {
    rd_integer(x);
}
void rd(ll &x) {
    rd_integer(x);
}
void rd(i128 &x) {
    rd_integer(x);
}
void rd(uint &x) {
    rd_integer(x);
}
void rd(ull &x) {
    rd_integer(x);
}
void rd(u128 &x) {
    rd_integer(x);
}
void rd(double &x) {
    rd_real(x);
}
void rd(long double &x) {
    rd_real(x);
}

template <class T, class U> void rd(pair<T, U> &p) {
    return rd(p.first), rd(p.second);
}
template <size_t N = 0, typename T> void rd_tuple(T &t) {
    if constexpr (N < std::tuple_size<T>::value) {
        auto &x = std::get<N>(t);
        rd(x);
        rd_tuple<N + 1>(t);
    }
}
template <class... T> void rd(tuple<T...> &tpl) {
    rd_tuple(tpl);
}

template <size_t N = 0, typename T> void rd(array<T, N> &x) {
    for (auto &d : x)
        rd(d);
}
template <class T> void rd(vector<T> &x) {
    for (auto &d : x)
        rd(d);
}

void read() {}
template <class H, class... T> void read(H &h, T &...t) {
    rd(h), read(t...);
}

void wt(const char c) {
    if (por == SZ)
        flush();
    obuf[por++] = c;
}
void wt(const string s) {
    for (char c : s)
        wt(c);
}
void wt(const char *s) {
    size_t len = strlen(s);
    for (size_t i = 0; i < len; i++)
        wt(s[i]);
}

template <typename T> void wt_integer(T x) {
    if (por > SZ - 100)
        flush();
    if (x < 0) {
        obuf[por++] = '-', x = -x;
    }
    int outi;
    for (outi = 96; x >= 10000; outi -= 4) {
        memcpy(out + outi, pre.num[x % 10000], 4);
        x /= 10000;
    }
    if (x >= 1000) {
        memcpy(obuf + por, pre.num[x], 4);
        por += 4;
    } else if (x >= 100) {
        memcpy(obuf + por, pre.num[x] + 1, 3);
        por += 3;
    } else if (x >= 10) {
        int q = (x * 103) >> 10;
        obuf[por] = q | '0';
        obuf[por + 1] = (x - q * 10) | '0';
        por += 2;
    } else
        obuf[por++] = x | '0';
    memcpy(obuf + por, out + outi + 4, 96 - outi);
    por += 96 - outi;
}

template <typename T> void wt_real(T x) {
    ostringstream oss;
    oss << fixed << setprecision(15) << double(x);
    string s = oss.str();
    wt(s);
}

void wt(int x) {
    wt_integer(x);
}
void wt(ll x) {
    wt_integer(x);
}
void wt(i128 x) {
    wt_integer(x);
}
void wt(uint x) {
    wt_integer(x);
}
void wt(ull x) {
    wt_integer(x);
}
void wt(u128 x) {
    wt_integer(x);
}
void wt(double x) {
    wt_real(x);
}
void wt(long double x) {
    wt_real(x);
}

template <class T, class U> void wt(const pair<T, U> val) {
    wt(val.first);
    wt(' ');
    wt(val.second);
}
template <size_t N = 0, typename T> void wt_tuple(const T t) {
    if constexpr (N < std::tuple_size<T>::value) {
        if constexpr (N > 0) {
            wt(' ');
        }
        const auto x = std::get<N>(t);
        wt(x);
        wt_tuple<N + 1>(t);
    }
}
template <class... T> void wt(tuple<T...> tpl) {
    wt_tuple(tpl);
}
template <class T, size_t S> void wt(const array<T, S> val) {
    auto n = val.size();
    for (size_t i = 0; i < n; i++) {
        if (i)
            wt(' ');
        wt(val[i]);
    }
}
template <class T> void wt(const vector<T> val) {
    auto n = val.size();
    for (size_t i = 0; i < n; i++) {
        if (i)
            wt(' ');
        wt(val[i]);
    }
}

void print() {
    wt('\n');
}
template <class Head, class... Tail> void print(Head &&head, Tail &&...tail) {
    wt(head);
    if (sizeof...(Tail))
        wt(' ');
    print(forward<Tail>(tail)...);
}
void __attribute__((destructor)) _d() {
    flush();
}
} // namespace fastio


using fastio::flush;
using fastio::print;
using fastio::read;

inline void first(bool i = true) {
    print(i ? "first" : "second");
}
inline void Alice(bool i = true) {
    print(i ? "Alice" : "Bob");
}
inline void Takahashi(bool i = true) {
    print(i ? "Takahashi" : "Aoki");
}
inline void yes(bool i = true) {
    print(i ? "yes" : "no");
}
inline void Yes(bool i = true) {
    print(i ? "Yes" : "No");
}
inline void No() {
    print("No");
}
inline void YES(bool i = true) {
    print(i ? "YES" : "NO");
}
inline void NO() {
    print("NO");
}
inline void Yay(bool i = true) {
    print(i ? "Yay!" : ":(");
}
inline void Possible(bool i = true) {
    print(i ? "Possible" : "Impossible");
}
inline void POSSIBLE(bool i = true) {
    print(i ? "POSSIBLE" : "IMPOSSIBLE");
}

/**
 * @brief Fast IO
 */

int main() {
    int N, M;
    cin >> M >> N;
    vector<vector<char>> C(N, vector<char>(M));
    rrep(j,0,M) {
        rep(i,0,N) cin >> C[i][j];
    }
    rep(i,0,N) C[i].push_back('.');
    C.push_back(vector<char>(M+1,'.'));
    int COUNT = 1;
    rep(i,0,N) {
        if (C[i][0] == '#' && C[i+1][0] == '.') COUNT++;
    }
    vector<pair<pair<int,int>,int>> V;
    rep(i,1,N+1) {
        rep(j,1,M+1) {
            char a = C[i-1][j-1], b = C[i][j-1], c = C[i-1][j], d = C[i][j];
            if (a == b && a != c && a == d) V.push_back({{i,j},1});
            if (a != b && a == c && a == d) V.push_back({{i,j},-1});
        }
    }
    sort(V.begin(), V.end(), [](pair<pair<int,int>,int> P1, pair<pair<int,int>,int> P2) {
        if (P1.first.first * P2.first.second == P1.first.second * P2.first.first) return P1.second < P2.second;
        return P1.first.second * P2.first.first < P1.first.first * P2.first.second;
    });
    int ANS = COUNT;
    for (pair<pair<int,int>,int> P : V) {
        COUNT += P.second;
        chmax(ANS,COUNT);
    }
    cout << ANS << endl;
}
accuracy: 1
time_ms: 10
memory_kb: 5584
final_rank: 3

code_snippet: //#define _GLIBCXX_DEBUG

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

#define endl '\n'
#define lfs cout<<fixed<<setprecision(10)
#define ALL(a)  (a).begin(),(a).end()
#define ALLR(a)  (a).rbegin(),(a).rend()
#define UNIQUE(a) (a).erase(unique((a).begin(),(a).end()),(a).end())
#define spa << " " <<
#define fi first
#define se second
#define MP make_pair
#define MT make_tuple
#define PB push_back
#define EB emplace_back
#define rep(i,n,m) for(ll i = (n); i < (ll)(m); i++)
#define rrep(i,n,m) for(ll i = (ll)(m) - 1; i >= (ll)(n); i--)
using ll = long long;
using ld = long double;
const ll MOD1 = 1e9+7;
const ll MOD9 = 998244353;
const ll INF = 1e18;
using P = pair<ll, ll>;
template<typename T> using PQ = priority_queue<T>;
template<typename T> using QP = priority_queue<T,vector<T>,greater<T>>;
template<typename T1, typename T2>bool chmin(T1 &a,T2 b){if(a>b){a=b;return true;}else return false;}
template<typename T1, typename T2>bool chmax(T1 &a,T2 b){if(a<b){a=b;return true;}else return false;}
ll median(ll a,ll b, ll c){return a+b+c-max({a,b,c})-min({a,b,c});}
void ans1(bool x){if(x) cout<<"Yes"<<endl;else cout<<"No"<<endl;}
void ans2(bool x){if(x) cout<<"YES"<<endl;else cout<<"NO"<<endl;}
void ans3(bool x){if(x) cout<<"Yay!"<<endl;else cout<<":("<<endl;}
template<typename T1,typename T2>void ans(bool x,T1 y,T2 z){if(x)cout<<y<<endl;else cout<<z<<endl;}
template<typename T1,typename T2,typename T3>void anss(T1 x,T2 y,T3 z){ans(x!=y,x,z);};
template<typename T>void debug(const T &v,ll h,ll w,string sv=" "){for(ll i=0;i<h;i++){cout<<v[i][0];for(ll j=1;j<w;j++)cout<<sv<<v[i][j];cout<<endl;}};
template<typename T>void debug(const T &v,ll n,string sv=" "){if(n!=0)cout<<v[0];for(ll i=1;i<n;i++)cout<<sv<<v[i];cout<<endl;};
template<typename T>void debug(const vector<T>&v){debug(v,v.size());}
template<typename T>void debug(const vector<vector<T>>&v){for(auto &vv:v)debug(vv,vv.size());}
template<typename T>void debug(stack<T> st){while(!st.empty()){cout<<st.top()<<" ";st.pop();}cout<<endl;}
template<typename T>void debug(queue<T> st){while(!st.empty()){cout<<st.front()<<" ";st.pop();}cout<<endl;}
template<typename T>void debug(deque<T> st){while(!st.empty()){cout<<st.front()<<" ";st.pop_front();}cout<<endl;}
template<typename T>void debug(PQ<T> st){while(!st.empty()){cout<<st.top()<<" ";st.pop();}cout<<endl;}
template<typename T>void debug(QP<T> st){while(!st.empty()){cout<<st.top()<<" ";st.pop();}cout<<endl;}
template<typename T>void debug(const set<T>&v){for(auto z:v)cout<<z<<" ";cout<<endl;}
template<typename T>void debug(const multiset<T>&v){for(auto z:v)cout<<z<<" ";cout<<endl;}
template<typename T,size_t size>void debug(const array<T, size> &a){for(auto z:a)cout<<z<<" ";cout<<endl;}
template<typename T,typename V>void debug(const map<T,V>&v){for(auto z:v)cout<<"["<<z.first<<"]="<<z.second<<",";cout<<endl;}
template<typename T>vector<vector<T>>vec(ll x, ll y, T w){vector<vector<T>>v(x,vector<T>(y,w));return v;}
ll gcd(ll x,ll y){ll r;while(y!=0&&(r=x%y)!=0){x=y;y=r;}return y==0?x:y;}
//vector<ll>dx={1,-1,0,0,1,1,-1,-1};vector<ll>dy={0,0,1,-1,1,-1,1,-1};
template<typename T>vector<T> make_v(size_t a,T b){return vector<T>(a,b);}
template<typename... Ts>auto make_v(size_t a,Ts... ts){return vector<decltype(make_v(ts...))>(a,make_v(ts...));}
template<typename T1, typename T2>ostream &operator<<(ostream &os, const pair<T1, T2>&p){return os << p.first << " " << p.second;}
template<typename T>ostream &operator<<(ostream &os, const vector<T> &v){for(auto &z:v)os << z << " ";cout<<"|"; return os;}
template<typename T>void rearrange(vector<int>&ord, vector<T>&v){
  auto tmp = v;
  for(int i=0;i<tmp.size();i++)v[i] = tmp[ord[i]];
}
template<typename Head, typename... Tail>void rearrange(vector<int>&ord,Head&& head, Tail&&... tail){
  rearrange(ord, head);
  rearrange(ord, tail...);
}
template<typename T> vector<int> ascend(const vector<T>&v){
  vector<int>ord(v.size());iota(ord.begin(),ord.end(),0);
  sort(ord.begin(),ord.end(),[&](int i,int j){return v[i]<v[j];});
  return ord;
}
template<typename T> vector<int> descend(const vector<T>&v){
  vector<int>ord(v.size());iota(ord.begin(),ord.end(),0);
  sort(ord.begin(),ord.end(),[&](int i,int j){return v[i]>v[j];});
  return ord;
}
template<typename T> vector<T> inv_perm(const vector<T>&ord){
  vector<T>inv(ord.size());
  for(int i=0;i<ord.size();i++)inv[ord[i]] = i;
  return inv;
}
ll FLOOR(ll n,ll div){assert(div>0);return n>=0?n/div:(n-div+1)/div;}
ll CEIL(ll n,ll div){assert(div>0);return n>=0?(n+div-1)/div:n/div;}
ll digitsum(ll n){ll ret=0;while(n){ret+=n%10;n/=10;}return ret;}
ll modulo(ll n,ll d){return (n%d+d)%d;};
template<typename T>T min(const vector<T>&v){return *min_element(v.begin(),v.end());}
template<typename T>T max(const vector<T>&v){return *max_element(v.begin(),v.end());}
template<typename T>T acc(const vector<T>&v){return accumulate(v.begin(),v.end(),T(0));};
template<typename T>T reverse(const T &v){return T(v.rbegin(),v.rend());};
//mt19937 mt(chrono::steady_clock::now().time_since_epoch().count());
int popcount(ll x){return __builtin_popcountll(x);};
int poplow(ll x){return __builtin_ctzll(x);};
int pophigh(ll x){return 63 - __builtin_clzll(x);};
template<typename T>T poll(queue<T> &q){auto ret=q.front();q.pop();return ret;};
template<typename T>T poll(priority_queue<T> &q){auto ret=q.top();q.pop();return ret;};
template<typename T>T poll(QP<T> &q){auto ret=q.top();q.pop();return ret;};
template<typename T>T poll(stack<T> &s){auto ret=s.top();s.pop();return ret;};
ll MULT(ll x,ll y){if(LLONG_MAX/x<=y)return LLONG_MAX;return x*y;}
ll POW2(ll x, ll k){ll ret=1,mul=x;while(k){if(mul==LLONG_MAX)return LLONG_MAX;if(k&1)ret=MULT(ret,mul);mul=MULT(mul,mul);k>>=1;}return ret;}
ll POW(ll x, ll k){ll ret=1;for(int i=0;i<k;i++){if(LLONG_MAX/x<=ret)return LLONG_MAX;ret*=x;}return ret;}
template< typename T = int >
struct edge {
  int to;
  T cost;
  int id;
  edge():id(-1){};
  edge(int to, T cost = 1, int id = -1):to(to), cost(cost), id(id){}
  operator int() const { return to; }
};

template<typename T>
using Graph = vector<vector<edge<T>>>;
template<typename T>
Graph<T>revgraph(const Graph<T> &g){
  Graph<T>ret(g.size());
  for(int i=0;i<g.size();i++){
    for(auto e:g[i]){
      int to = e.to;
      e.to = i;
      ret[to].push_back(e);
    }
  }
  return ret;
}
template<typename T>
Graph<T> readGraph(int n,int m,int indexed=1,bool directed=false,bool weighted=false){
  Graph<T> ret(n);
  for(int es = 0; es < m; es++){
    int u,v;
    T w=1;
    cin>>u>>v;u-=indexed,v-=indexed;
    if(weighted)cin>>w;
    ret[u].emplace_back(v,w,es);
    if(!directed)ret[v].emplace_back(u,w,es);
  }
  return ret;
}
template<typename T>
Graph<T> readParent(int n,int indexed=1,bool directed=true){
  Graph<T>ret(n);
  for(int i=1;i<n;i++){
    int p;cin>>p;
    p-=indexed;
    ret[p].emplace_back(i);
    if(!directed)ret[i].emplace_back(p);
  }
  return ret;
}

template <typename F>
class
#if defined(__has_cpp_attribute) && __has_cpp_attribute(nodiscard)
  [[nodiscard]]
#endif  // defined(__has_cpp_attribute) && __has_cpp_attribute(nodiscard)
FixPoint final : private F
{
public:
  template <typename G>
  explicit constexpr FixPoint(G&& g) noexcept
    : F{std::forward<G>(g)}
  {}

  template <typename... Args>
  constexpr decltype(auto)
  operator()(Args&&... args) const
#if !defined(__GNUC__) || defined(__clang__) || __GNUC__ >= 9
  noexcept(noexcept(F::operator()(std::declval<FixPoint>(), std::declval<Args>()...)))
#endif  // !defined(__GNUC__) || defined(__clang__) || __GNUC__ >= 9
  {
    return F::operator()(*this, std::forward<Args>(args)...);
  }
};  // class FixPoint


#if defined(__cpp_deduction_guides)
template <typename F>
FixPoint(F&&)
-> FixPoint<std::decay_t<F>>;
#endif  // defined(__cpp_deduction_guides)


namespace
{
  template <typename F>
#if !defined(__has_cpp_attribute) || !__has_cpp_attribute(nodiscard)
  #  if defined(__GNUC__) && (__GNUC__ > 3 || __GNUC__ == 3 && __GNUC_MINOR__ >= 4)
  __attribute__((warn_unused_result))
#  elif defined(_MSC_VER) && _MSC_VER >= 1700 && defined(_Check_return_)
  _Check_return_
#  endif  // defined(__GNUC__) && (__GNUC__ > 3 || __GNUC__ == 3 && __GNUC_MINOR__ >= 4)
#endif  // !defined(__has_cpp_attribute) || !__has_cpp_attribute(nodiscard)
  inline constexpr decltype(auto)
  makeFixPoint(F&& f) noexcept
  {
    return FixPoint<std::decay_t<F>>{std::forward<std::decay_t<F>>(f)};
  }
}  // namespace

using Real = long double;
using Point = complex<Real>;
const Real EPS = 1e-10, PI = acos((Real)(-1.0));

inline bool eq(Real a, Real b) { return fabs(b - a) < EPS; }
inline bool eq(Point a, Point b) { return fabs(b - a) < EPS; }

Point operator*(const Point &p, const Real &d) {
  return Point(real(p) * d, imag(p) * d);
}

istream &operator>>(istream &is, Point &p) {
  Real a, b;
  is >> a >> b;
  p = Point(a, b);
  return is;
}

ostream &operator<<(ostream &os, Point &p) {
  return os << fixed << setprecision(10) << p.real() << " " << p.imag();
}

Point rotate(Real theta, const Point &p) {
  return Point(cos(theta) * p.real() - sin(theta) * p.imag(), sin(theta) * p.real() + cos(theta) * p.imag());
}

namespace std {
  bool operator<(const Point& a, const Point& b) {
    return !eq(a.real(), b.real()) ? a.real() < b.real() : a.imag() < b.imag();
  }
}

struct Line {
  Point a, b;
  Line() = default;
  Line(Point a, Point b): a(a), b(b) {}

  friend ostream &operator<<(ostream &os, Line &p) {
    return os << p.a << " to " << p.b;
  }

  friend istream &operator>>(istream &is, Line &a) {
    return is >> a.a >> a.b;
  }
};

struct Circle {
  Point c;
  Real r;
  Circle() = default;
  Circle(Point c, Real r): c(c), r(r) {}

  friend ostream &operator<<(ostream &os, Circle &c) {
    return os << c.c << ": " << c.r;
  }

  friend istream &operator>>(istream &is, Circle &c) {
    return is >> c.c >> c.r;
  }
};

Real cross(const Point &a, const Point &b) {
  return real(a) * imag(b) - real(b) * imag(a);
}

Real dot(const Point &a, const Point &b) {
  return real(a) * real(b) + imag(a) * imag(b);
}

struct Segment : Line {
  Segment() = default;
  Segment(Point a, Point b) : Line(a, b) {}
};

int ccw(const Point &a, Point b, Point c) {
  b = b - a, c = c - a;
  if (cross(b, c) > EPS) return +1; // COUNTER_CLOCKWISE
  if (cross(b, c) < -EPS) return -1; // CLOCKWISE
  if (dot(b, c) < 0) return +2; // ONLINE_BACK
  if (norm(b) < norm(c)) return -2; // ONLINE_FRONT
  return 0; // ON_SEGMENT
}

bool intersect(const Segment &s, const Point &p) {
  return ccw(s.a, s.b, p) == 0;
}

bool intersect(const Segment &s, const Segment&t) {
  return ccw(s.a, s.b, t.a) * ccw(s.a, s.b, t.b) <= 0 && ccw(t.a, t.b, s.a) * ccw(t.a, t.b, s.b) <= 0;
}

bool intersect(const Line &l, const Segment& s) {
  return cross(l.b - l.a, s.a - l.a) * cross(l.b - l.a, s.b - l.a) < EPS;
}

int intersect(const Circle &c, const Circle &d) {
  Real dis = fabs(c.c - d.c);

  if (dis > c.r + d.r + EPS) return 4;
  else if (eq(dis, c.r + d.r)) return 3;
  else if (eq(dis, abs(c.r - d.r))) return 1;
  else if (dis + min(c.r, d.r) < max(c.r, d.r) - EPS) return 0;
  else return 2;
}

bool parallel(const Line &a, const Line &b) {
  return abs(cross(a.b - a.a, b.b - b.a)) < EPS;
}

bool orthogonal(const Line &a, const Line &b) {
  return abs(dot(a.b - a.a, b.b - b.a)) < EPS;
}

Point projection(const Line& s, const Point &p) {
  double t = dot(p - s.a, s.b - s.a) / norm(s.b - s. a);
  return s.a + (s.b - s.a) * t;
}

Point projection(const Segment& l, const Point &p) {
  return projection(Line(l), p);
}

Point reflection(const Line &l, const Point &p) {
  Point r = projection(l, p);
  return p + (r - p) * 2;
}

Real distance(const Line &l, const Point &p) {
  Point r = projection(l, p);
  return fabs(p - r);
}

Real distance(const Segment&s, const Point &p) {
  Point r = projection(s, p);
  if (intersect(s, r)) return abs(r - p);
  return min(abs(s.a - p), abs(s.b - p));
}

Real distance(const Segment& a, const Segment& b) {
  if (intersect(a, b)) return 0;
  return min({
               distance(a, b.a),
               distance(a, b.b),
               distance(b, a.a),
               distance(b, a.b)
             });
}

bool contains(const Circle &c, const Point &p) {
  if (fabs(c.c - p) < c.r + EPS) return true;
  return false;
}

Point crosspoint(const Line &l, const Line &m) {
  Real A = cross(l.b - l.a, m.b - m.a);
  Real B = cross(l.b - l.a, l.b - m.a);
  if (eq(abs(A), 0.0) && eq(abs(B), 0.0)) return m.a;
  return m.a + (m.b - m.a) * B / A;
}

Point crosspoint(const Segment& l, const Segment& m) {
  return crosspoint(Line(l), Line(m));
}

Line bisector_of_angle(const Point& a, const Point& b, const Point& c) {
  Real d_ab = fabs(a - b);
  Real d_bc = fabs(b - c);
  Point c_ = b + (c - b) * d_ab / d_bc;

  return Line(b, (a + c_) * 0.5);
}

Line bisector(const Point& a, const Point& b) {
  Point c = (a + b) * 0.5;
  Point d = c + rotate(PI / 2, b - c);

  return Line(c, d);
}

int intersect(const Circle &c, const Line &l) {
  Real d = distance(l, c.c);

  if (d > c.r + EPS) return 0;
  if (eq(d, c.r)) return 1;
  return 2;
}

pair<Point, Point> crosspoint(const Circle& c, const Line& l) {
  Real d = distance(l, c.c);

  Point p = projection(l, c.c);
  if (intersect(c, l) == 1) return { p, p };

  Real d2 = sqrt(c.r * c.r - d * d);
  Point v = (l.a - l.b) * (1.0 / fabs(l.a - l.b));

  return { p + d2 * v, p - d2 * v };
}

vector<Point> crosspoint(const Circle &c, const Segment &s) {
  int isect = intersect(c, Line(s));
  if (isect == 0) return {};

  auto [p1, p2] = crosspoint(c, Line(s));

  vector<Point> res;
  if (ccw(s.a, s.b, p1) == 0) res.push_back(p1);
  if (ccw(s.a, s.b, p2) == 0) res.push_back(p2);

  if (res.size() == 2 && ccw(s.a, p1, p2) == 0) swap(res[0], res[1]);
  return res;
}

pair<Point, Point> crosspoint(const Circle &c1, const Circle &c2) {
  Real d = fabs(c1.c - c2.c);
  Real x1 = (c1.r * c1.r + d * d - c2.r * c2.r) / 2 / d;
  Real y = sqrt(c1.r * c1.r - x1 * x1);

  Point base = (c2.c * x1 + c1.c * (d - x1)) * (1.0 / d);
  Point v = rotate(PI / 2, c1.c - base);
  v = v / fabs(v);

  return { base + v * y, base - v * y };
}

pair<Point, Point> tangent(const Circle &c, const Point &p) {
  Real d = fabs(c.c - p);
  Real d2 = sqrt(d * d - c.r * c.r);
  Real a = acos(d2 / d);


  Point q = c.c - p;
  q = q / fabs(q);

//  cout << d << " " << d2 << " " << a << " " << q << endl;
  return {
    p + rotate(a, q) * d2,
    p + rotate(-a, q) * d2
  };
}

vector<Segment> common_tangent(Circle c1, Circle c2) {
  int isect = intersect(c1, c2);
  Real d = fabs(c1.c - c2.c);
  Point v = (c2.c - c1.c) / d;

  vector<Segment> res;

  if (isect == 0) {
    return {};
  } else if (isect == 1) {
    auto [p1, p2] = crosspoint(c1, Line(c1.c, c2.c));
    if (eq(fabs(p2 - c2.c), c2.r)) swap(p1, p2);

    Point v = p1 + rotate(PI/2, c2.c - p1);
    return { Segment(p1, v) };
  } else if (isect == 2) {
  } else if (isect == 3) {
    auto [p1, p2] = crosspoint(c1, c2);
    res.emplace_back(p1, rotate(PI / 2, c1.c - p1) + p1);
  } else {
    Real a = d * c1.r / (c1.r + c2.r);
    Point p = c1.c + v * a;

    Real d1 = sqrt(a * a - c1.r * c1.r), d2 = sqrt(norm(p - c2.c) - c2.r * c2.r);
    Real theta = acos(d1 / a);

//    cout << d << endl;
//    cout << a << " " << d1 << " " << d2 << " " << theta << ": " << p << endl;

    Point e = (c1.c - p) * (1.0 / fabs(c1.c - p));
    Point e1 = rotate(theta, e), e2 = rotate(-theta, e);

    res.emplace_back(p + e1 * d1, p - e1 * d2);
    res.emplace_back(p + e2 * d1, p - e2 * d2);
  }

  if (eq(c1.r, c2.r)) {
    Point e = rotate(PI / 2, v);
    res.push_back(Segment(c1.c + e * c1.r, c2.c + e * c1.r));
    res.push_back(Segment(c1.c - e * c1.r, c2.c - e * c1.r));
    return res;
  }

  if (c1.r > c2.r) swap(c1, c2);

  v = c1.c - c2.c;
  Point p = v * (1.0 / (c2.r - c1.r)) * c2.r + c2.c;

  auto [q1, q2] = tangent(c1, p);
  res.emplace_back(q1, crosspoint(c2, Line(p, q1)).first);
  res.emplace_back(q2, crosspoint(c2, Line(p, q2)).first);

  return res;
}

using Polygon = vector<Point>;

istream& operator>>(istream& is, Polygon &p) {
  for (int i = 0; i < p.size(); i++) is >> p[i];
  return is;
}

ostream& operator<<(ostream& os, Polygon &p) {
  for (int i = 0; i < p.size(); i++) os << p[i];
  return os;
}

Real area(const Polygon& p) {
  Real res = 0;
  for (int i = 0; i < p.size(); i++) {
    res += cross(p[i], p[(i + 1) % p.size()]);
  }
  return abs(res)/2;
}

Real arcarea(const Circle &c, const Point &p1_, const Point &p2_) {
  Point p1 = p1_ - c.c, p2 = p2_ - c.c;
  Real a2 = atan2(imag(p2), real(p2));
  Point p = rotate(-a2, p1);
  Real a1 = atan2(imag(p), real(p));
//  cout << p1 << " " << p2 << " --- " << a2 << " " << a1 << endl;
  return - a1 / 2 * c.r * c.r;
}

int contains(Polygon g,Point p){
  int n=g.size();
  bool x=false;
  for(int i=0;i<n;i++){
    Point a=g[i]-p,b=g[(i+1)%n]-p;
    if(fabs(cross(a,b)) < EPS and dot(a,b) < EPS) return 1;
    if(a.imag()>b.imag()) swap(a,b);
    if(a.imag() < EPS and EPS < b.imag() and cross(a,b) > EPS ) {
//      cout << a << " --- " << b << ": " << cross(a, b) << endl;
      x = !x;
    }
  }
  return (x?2:0);
}

Polygon convex_hull(Polygon Q) {
  sort(ALL(Q));

  Polygon upper({Q[0]}), lower({Q[0]});

  rep(i, 1, Q.size()) {
    while (upper.size() >= 2) {
      int _ccw = ccw(upper[upper.size() - 2], upper[upper.size() - 1], Q[i]);
      if (_ccw == 1) {
        upper.pop_back();
      } else {
        break;
      }
    }
    if (upper.size() <= 1) {
      upper.push_back(Q[i]);
    } else if (upper.size() > 1) {
      int _ccw = ccw(upper[upper.size() - 2], upper[upper.size() - 1], Q[i]);
      if (_ccw == -1 || _ccw == -2) {
        upper.push_back(Q[i]);
      }
    }
  }
  rep(i, 1, Q.size()) {
    while (lower.size() >= 2) {
      int _ccw = ccw(lower[lower.size() - 2], lower[lower.size() - 1], Q[i]);
      if (_ccw == -1) {
        lower.pop_back();
      } else {
        break;
      }
    }

    if (lower.size() <= 1) {
      lower.push_back(Q[i]);
    } else if (lower.size() > 1) {
      int _ccw = ccw(lower[lower.size() - 2], lower[lower.size() - 1], Q[i]);
      if (_ccw == 1 || _ccw == -2) {
        lower.push_back(Q[i]);
      }
    }
  }

  Polygon ret;

  rep(i, 0, lower.size()) {
    ret.push_back(lower[i]);
//    cout << lower[i] << endl;
  }

//  cout << " | " << endl;

  rrep(i, 0, upper.size()) {
    if (!eq(lower[0], upper[i]) && !eq(lower.back(), upper[i]))
      ret.push_back(upper[i]);
//    cout << upper[i] << endl;
  }

  int start = 0;

//  cout << ret.size() << endl;
  rep(i, 0, ret.size()) {
    if (ret[i].imag() < ret[start].imag() || (eq(ret[i].imag(), ret[start].imag()) && ret[i].real() < ret[start].real())) {
      start = i;
    }
  }

  cout << ret.size() << endl;
  rep(i, 0, ret.size()) {
    auto p = ret[(i + start) % ret.size()];
    cout << (int)p.real() << " " << (int)p.imag() << endl;
  }

  return ret;
}

Real closest_pair(vector<Point> &pts, int l, int r) {
  int m = (l + r) / 2;
  if (r - l <= 1) {
    return INF;
  } else if (r - l == 2) {
    if (imag(pts[l]) > imag(pts[l + 1])) swap(pts[l], pts[l + 1]);
    return fabs(pts[l] - pts[l + 1]);
  }

  Real mid = pts[m].real();
  Real d = min(closest_pair(pts, l, m), closest_pair(pts, m, r));

  inplace_merge(pts.begin() + l, pts.begin() + m, pts.begin() + r, [](const Point &a, const Point& b) {
    return a.imag() < b.imag();
  });

  vector<Point> ret;

  for (int i = l; i < r; i++) {
    if (fabs(pts[i].real() - mid) >= d) continue;

    for (int j = ret.size() - 1; j >= 0; j--) {
      if (fabs(imag(ret[j]) - imag(pts[i])) >= d) break;
      chmin(d, fabs(ret[j] - pts[i]));
    }

    ret.emplace_back(pts[i]);
  }

  return d;
}

int main() {
  cout << fixed << setprecision(10);

  int H, W;
  cin >> H >> W;
  vector<string> s(H);

  rep(i, 0, H) cin >> s[i];

  ll res = 1;
  ll cnt = 1;

  vector<P> pts;
  rep(i, 0, H + 1) {
    rep(j, 0, W + 1) {
      if (i == 0 && j == 0) continue;
      pts.emplace_back(i, j);
    }
  }

  auto same = [](P a, P b) {
    return a.fi * b.se - b.fi * a.se == 0;
  };

  auto cmp = [](const P &a, const P &b) {
    return a.fi * b.se - b.fi * a.se > 0;
  };

  sort(ALL(pts), cmp);

  auto in = [&](int y, int x) {
    return 0 <= y && y < H && 0 <= x && x < W;
  };

  auto tp = [&](int y, int x) {
    string t("....");
    y = H - y;
    if (in(y - 1, x - 1) && s[y - 1][x - 1] == '#') t[0] = '#';
    if (in(y - 1, x) && s[y - 1][x] == '#') t[1] = '#';
    if (in(y, x - 1) && s[y][x - 1] == '#') t[2] = '#';
    if (in(y, x) && s[y][x] == '#') t[3] = '#';
//    cout << y << " " << x << ": " << t << endl;

    if (t == "...#" || t == "###.") return 1;
    if (t == "#..." || t == ".###") return -1;
    return 0;
  };

  rep(i, 0, pts.size()) {
    cnt += tp(pts[i].fi, pts[i].se);

    while (i < pts.size() && same(pts[i], pts[i+1])) {
      i++;
      cnt += tp(pts[i].fi, pts[i].se);
    }
//    cout << cnt << endl;
    chmax(res, cnt);
  }

  cout << res << endl;
}
accuracy: 1
time_ms: 30
memory_kb: 13768
final_rank: 17

code_snippet: #include <bits/stdc++.h>
#include <complex>
#include <random>
using namespace std;
//#include <atcoder/all>
//using namespace atcoder;
using ll = long long;
using vll = vector<ll>;
using vvll = vector<vll>;
using vvvll = vector<vvll>;
using vvvvll = vector<vvvll>;
using vvvvvll = vector<vvvvll>;
using vvvvvvll = vector<vvvvvll>;
using vb = vector<bool>;
using vvb = vector<vb>;
using vvvb = vector<vvb>;
using vvvvb = vector<vvvb>;
using vd = vector<double>;
using vvd = vector<vd>;
using vvvd = vector<vvd>;
using vvvvd = vector<vvvd>;
using vvvvvd = vector<vvvvd>;
#define all(A) A.begin(),A.end()
#define ALL(A) A.begin(),A.end()
#define rep(i, n) for (ll i = 0; i < (ll) (n); i++)
using pqr = priority_queue<pair<ll, ll>, vector<pair<ll, ll>>, greater<pair<ll, ll>>>;
#define tN(t) (t==1?XN:YN)
#define tS(t) (t==1?XS:YS)
#define tA(t) (t==1?XA:YA)

template<class T>
bool chmax(T& p, T q, bool C = 1) {
    if (C == 0 && p == q) {
        return 1;
    }
    if (p < q) {
        p = q;
        return 1;
    }
    else {
        return 0;
    }
}

template<class T>
bool chmin(T& p, T q, bool C = 1) {
    if (C == 0 && p == q) {
        return 1;
    }
    if (p > q) {
        p = q;
        return 1;
    }
    else {
        return 0;
    }
}

ll gcd(ll(a), ll(b)) {
    if (b == 0)return a;
    ll c = a;
    while (a % b != 0) {
        c = a % b;
        a = b;
        b = c;
    }
    return b;
}
ll sqrtz(ll N) {
    ll L = 0;
    ll R = sqrt(N) + 10000;
    while (abs(R - L) > 1) {
        ll mid = (R + L) / 2;
        if (mid * mid <= N)L = mid;
        else R = mid;
    }
    return L;

}

vector<ll> fact, factinv, inv;
ll mod = 1e9 + 7;
void prenCkModp(ll n) {
    fact.resize(n + 5);
    factinv.resize(n + 5);
    inv.resize(n + 5);
    fact.at(0) = fact.at(1) = 1;
    factinv.at(0) = factinv.at(1) = 1;
    inv.at(1) = 1;
    for (ll i = 2; i < n + 5; i++) {
        fact.at(i) = (fact.at(i - 1) * i) % mod;
        inv.at(i) = mod - (inv.at(mod % i) * (mod / i)) % mod;
        factinv.at(i) = (factinv.at(i - 1) * inv.at(i)) % mod;
    }

}
ll nCk(ll n, ll k) {
    if (n < k) return 0;
    return fact.at(n) * (factinv.at(k) * factinv.at(n - k) % mod) % mod;
}



ll modPow(ll a, ll n, ll p) {
    ll res = 1;
    ll k = a;
    while (n > 0) {
        if (n % 2 == 1) {
            res *= k;
            if (res > p)res %= p;
        }
        k = k * k;
        if (k > p)k %= p;
        n /= 2;
    }
    return res;
}

struct quot {
    ll de, nu;//de分母
    quot() = default;
    quot(ll nu, ll de) :de(de), nu(nu) { init(*this); }
    quot(ll z) :de(1), nu(z) { init(*this); }
    void init(quot& a) {
        if (a.nu == 0) {
            a.de = 1;
        }
        else {
            ll g = GcD(a.de, a.nu);
            a.de /= g;
            a.nu /= g;
            if (a.de < 0) {
                a.de *= -1;
                a.nu *= -1;
            }
        }
    }
    ll GcD(ll(a), ll(b)) {
        ll c = a;
        while (a % b != 0) {
            c = a % b;
            a = b;
            b = c;
        }
        return b;
    }

    quot operator *(const quot& p) {
        quot res;
        res.de = this->de * p.de;
        res.nu = this->nu * p.nu;
        init(res);
        return res;
    };
    quot operator +(const quot& p) {
        quot res;
        res.de = this->de * p.de;
        res.nu = this->nu * p.de + this->de * p.nu;
        init(res);
        return res;
    };

    quot operator-()const {
        quot res;
        res.de = this->de;
        res.nu = -this->nu;
        return res;
    };
    quot operator -(const quot& p) {
        return *this + (-p);
    };
    quot inv(quot q) {
        quot res;
        res.de = q.nu;
        res.nu = q.de;
        return res;
    }
    quot operator/(const quot& q) {
        return *this * inv(q);
    }

    bool operator==(const quot& q) {
        return (this->de == q.de && this->nu == q.nu);
    }

    bool operator<(const quot& q)const {
        return (this->nu * q.de - this->de * q.nu < 0);
    }
    bool operator>(const quot& q) {
        return !(*this == q || *this < q);
    }

    double tod(const quot& q) {
        return (double(nu) / double(de));
    }

    void print() {
        cout << nu << " " << de << endl;
    }

    void printd() {
        cout << tod(*this) << endl;
    }
};






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

    ll H, W,an=0,m=1;
    cin >> H >> W;
    map<quot, ll> M;
    vector<string> S(H + 2, "");
    rep(w, W + 2)S[0].push_back('.'), S[H + 1].push_back('.');
    rep(h, H) {
        cin >> S[h+1];
        S[h+1] = '.' + S[h+1] + '.';
    }
    rep(h, H + 1)rep(w, W + 1) {
            ll cnt = 0;
            rep(dh, 2)rep(dw, 2)cnt += (S[h + dh][w + dw] == '#');
            if (cnt == 1) {
                if (S[h][w] == '#')M[quot(H - h, w)]++;
                else if (S[h + 1][w + 1] == '#')M[quot(H - h, w)]--;
            }
            if (cnt == 3) {
                if (S[h][w] == '.')M[quot(H - h, w)]++;
                else if (S[h + 1][w + 1] == '.')M[quot(H - h, w)]--;
            }
    }
    for (auto p : M) {
        m += p.second;
        chmax(an, m);
    }
    cout << an << endl;
}
accuracy: 1
time_ms: 20
memory_kb: 8116
final_rank: 12

code_snippet: #include <bits/stdc++.h>
#include <complex>
#include <random>
using namespace std;
//#include <atcoder/all>
//using namespace atcoder;
using ll = long long;
using vll = vector<ll>;
using vvll = vector<vll>;
using vvvll = vector<vvll>;
using vvvvll = vector<vvvll>;
using vvvvvll = vector<vvvvll>;
using vvvvvvll = vector<vvvvvll>;
using vb = vector<bool>;
using vvb = vector<vb>;
using vvvb = vector<vvb>;
using vvvvb = vector<vvvb>;
using vd = vector<double>;
using vvd = vector<vd>;
using vvvd = vector<vvd>;
using vvvvd = vector<vvvd>;
using vvvvvd = vector<vvvvd>;
#define all(A) A.begin(),A.end()
#define ALL(A) A.begin(),A.end()
#define rep(i, n) for (ll i = 0; i < (ll) (n); i++)
using pqr = priority_queue<pair<ll, ll>, vector<pair<ll, ll>>, greater<pair<ll, ll>>>;
#define tN(t) (t==1?XN:YN)
#define tS(t) (t==1?XS:YS)
#define tA(t) (t==1?XA:YA)

template<class T>
bool chmax(T& p, T q, bool C = 1) {
    if (C == 0 && p == q) {
        return 1;
    }
    if (p < q) {
        p = q;
        return 1;
    }
    else {
        return 0;
    }
}

template<class T>
bool chmin(T& p, T q, bool C = 1) {
    if (C == 0 && p == q) {
        return 1;
    }
    if (p > q) {
        p = q;
        return 1;
    }
    else {
        return 0;
    }
}

ll gcd(ll(a), ll(b)) {
    if (b == 0)return a;
    ll c = a;
    while (a % b != 0) {
        c = a % b;
        a = b;
        b = c;
    }
    return b;
}
ll sqrtz(ll N) {
    ll L = 0;
    ll R = sqrt(N) + 10000;
    while (abs(R - L) > 1) {
        ll mid = (R + L) / 2;
        if (mid * mid <= N)L = mid;
        else R = mid;
    }
    return L;

}

vector<ll> fact, factinv, inv;
ll mod = 1e9 + 7;
void prenCkModp(ll n) {
    fact.resize(n + 5);
    factinv.resize(n + 5);
    inv.resize(n + 5);
    fact.at(0) = fact.at(1) = 1;
    factinv.at(0) = factinv.at(1) = 1;
    inv.at(1) = 1;
    for (ll i = 2; i < n + 5; i++) {
        fact.at(i) = (fact.at(i - 1) * i) % mod;
        inv.at(i) = mod - (inv.at(mod % i) * (mod / i)) % mod;
        factinv.at(i) = (factinv.at(i - 1) * inv.at(i)) % mod;
    }

}
ll nCk(ll n, ll k) {
    if (n < k) return 0;
    return fact.at(n) * (factinv.at(k) * factinv.at(n - k) % mod) % mod;
}



ll modPow(ll a, ll n, ll p) {
    ll res = 1;
    ll k = a;
    while (n > 0) {
        if (n % 2 == 1) {
            res *= k;
            if (res > p)res %= p;
        }
        k = k * k;
        if (k > p)k %= p;
        n /= 2;
    }
    return res;
}

struct quot {
    ll de, nu;//de分母
    quot() = default;
    quot(ll nu, ll de) :de(de), nu(nu) { init(*this); }
    quot(ll z) :de(1), nu(z) { init(*this); }
    void init(quot& a) {
        if (a.nu == 0) {
            a.de = 1;
        }
        else {
            ll g = GcD(a.de, a.nu);
            a.de /= g;
            a.nu /= g;
            if (a.de < 0) {
                a.de *= -1;
                a.nu *= -1;
            }
        }
    }
    ll GcD(ll(a), ll(b)) {
        ll c = a;
        while (a % b != 0) {
            c = a % b;
            a = b;
            b = c;
        }
        return b;
    }

    quot operator *(const quot& p) {
        quot res;
        res.de = this->de * p.de;
        res.nu = this->nu * p.nu;
        init(res);
        return res;
    };
    quot operator +(const quot& p) {
        quot res;
        res.de = this->de * p.de;
        res.nu = this->nu * p.de + this->de * p.nu;
        init(res);
        return res;
    };

    quot operator-()const {
        quot res;
        res.de = this->de;
        res.nu = -this->nu;
        return res;
    };
    quot operator -(const quot& p) {
        return *this + (-p);
    };
    quot inv(quot q) {
        quot res;
        res.de = q.nu;
        res.nu = q.de;
        return res;
    }
    quot operator/(const quot& q) {
        return *this * inv(q);
    }

    bool operator==(const quot& q) {
        return (this->de == q.de && this->nu == q.nu);
    }

    bool operator<(const quot& q)const {
        return (this->nu * q.de - this->de * q.nu < 0);
    }
    bool operator>(const quot& q) {
        return !(*this == q || *this < q);
    }

    double tod(const quot& q) {
        return (double(nu) / double(de));
    }

    void print() {
        cout << nu << " " << de << endl;
    }

    void printd() {
        cout << tod(*this) << endl;
    }
};






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

    ll H, W;
    cin >> H >> W;
    map<quot, ll> M;
    vector<string> S(H + 2, "");
    rep(w, W + 2)S[0].push_back('.'), S[H + 1].push_back('.');
    rep(h, H) {
        cin >> S[h+1];
        S[h+1] = '.' + S[h+1] + '.';
    }
    rep(h, H + 1) {
        rep(w, W + 1) {
            ll cnt = 0;
            rep(dh, 2)rep(dw, 2) {
                cnt += (S[h + dh][w + dw] == '#');
                
            }
            if (cnt == 1) {
                if (S[h][w] == '#') {
                    M[quot(H - h, w)]++;
                }
                else if (S[h + 1][w + 1] == '#') {
                    M[quot(H - h, w)]--;
                }
            }
            if (cnt == 3) {
                if (S[h][w] == '.') {
                    M[quot(H - h, w)]++;
                }
                else if (S[h + 1][w + 1] == '.') {
                    M[quot(H - h, w)]--;
                }
            }
        }
    }
    ll an = 0;
    ll m = 1;
    for (auto p : M) {
        m += p.second;
        chmax(an, m);
    }
    cout << an << endl;



}
accuracy: 1
time_ms: 20
memory_kb: 8288
final_rank: 14

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

// template {{{
using i32 = int;
using u32 = unsigned int;
using i64 = long long;
using u64 = unsigned long long;

#define  range(i, l, r) for (i64 i = (i64)(l); i < (i64)(r); (i) += 1)
#define rrange(i, l, r) for (i64 i = (i64)(r) - 1; i >= (i64)(l); (i) -= 1)

#define  whole(f, x, ...) ([&](decltype((x)) container) { return (f)(  begin(container),  end(container), ## __VA_ARGS__); })(x)
#define rwhole(f, x, ...) ([&](decltype((x)) container) { return (f)( rbegin(container), rend(container), ## __VA_ARGS__); })(x)

#define debug(x) cerr << "(" << __LINE__ << ")" << #x << ": " << (x) << endl

constexpr i32 inf   = 1001001001;
constexpr i64 infll = 1001001001001001001ll;

constexpr i32 dx[] = {0, -1, 1, 0, -1, 1, -1, 1}; 
constexpr i32 dy[] = {-1, 0, 0, 1, -1, -1, 1, 1};

struct IoSetup { IoSetup(i32 x = 15){ cin.tie(0); ios::sync_with_stdio(0); cout << fixed << setprecision(x); cerr << fixed << setprecision(x); } } iosetup;

template <typename T = i64> T input() { T x; cin >> x; return x; }

template <typename T> ostream &operator<<(ostream &os, vector<T> &v) { range(i, 0, v.size()) { os << v[i] << (i + 1 != (int)v.size() ? " " : ""); } return os; } 
template <typename T> istream &operator>>(istream &is, vector<T> &v) { for (T &in : v) is >> in; return is; }

template <typename T1, typename T2> ostream &operator<<(ostream &os, pair<T1, T2> p) { os << "(" << p.first << ", " << p.second << ")"; return os; }
template <typename T1, typename T2> istream &operator>>(istream &is, pair<T1, T2> &p) { is >> p.first >> p.second; return is; }

template <typename T> vector<T> make_vector(size_t a, T b) { return vector<T>(a, b); }
template <typename... Ts> auto make_vector(size_t a, Ts... ts) { return vector<decltype(make_vector(ts...))>(a, make_vector(ts...)); }

template <typename T1, typename T2> inline bool chmax(T1 &a, T2 b) { return a < b && (a = b, true); }
template <typename T1, typename T2> inline bool chmin(T1 &a, T2 b) { return a > b && (a = b, true); }
// }}}

namespace intgeometry2d {
  using isize = std::ptrdiff_t;
  using usize = std::size_t;

  using i32 = std::int_fast32_t;
  using i64 = std::int_fast64_t;
  using u32 = std::uint_fast32_t;
  using u64 = std::uint_fast64_t;
} // intgeometry2d

namespace intgeometry2d {

  template< typename Z >
  class lattice_point {
    Z x_, y_;

  public:
    lattice_point() {}
    lattice_point(Z x_, Z y_) : x_(x_), y_(y_) {}
    
    Z x() const { return x_; }
    Z y() const { return y_; }

    bool operator==(const lattice_point &p) const { return x_ == p.x_ and y_ == p.y_; }
    bool operator!=(const lattice_point &p) const { return x_ != p.x_ or  y_ != p.y_; }

    lattice_point operator+(lattice_point p) { return lattice_point(x_ + p.x_, y_ + p.y_); }
    lattice_point operator-(lattice_point p) { return lattice_point(x_ - p.x_, y_ - p.y_); }

    Z norm() const { return x_ * x_ + y_ * y_; }
  };

} // intgeometry2d

namespace intgeometry2d {

  template< typename Z >
  Z det(const lattice_point<Z> &a, const lattice_point<Z> &b) {
    return a.x() * b.y() - a.y() * b.x();
  }

} // intgeometry2d

namespace intgeometry2d {
  template< typename Z >
  bool argcmp(const lattice_point<Z> &a, const lattice_point<Z> &b) {
    using std::pair;
    bool fa = pair(a.y(), a.x()) < pair<Z, Z>(0, 0);
    bool fb = pair(b.y(), b.x()) < pair<Z, Z>(0, 0);
    Z d = det(a, b);
    return fa != fb ? fa < fb : (d == 0 ? a.norm() < b.norm() : d > 0);
  }
} // intgeometry2d

void solve() {
  int h = input(), w = input();

  auto cs = make_vector(h + 2, w + 2, '.');
  range(i, 1, h + 1) range(j, 1, w + 1) {
    cin >> cs[i][j];
  }

  using point = intgeometry2d::lattice_point<i32>;
  vector< pair<point, int> > pts;
  rrange(i, 0, h + 1) range(j, 0, w + 1) {
    // cs[ i ][j] cs[ i ][j+1]
    // cs[i+1][j] cs[i+1][j+1]
    // centor: (h - i, j) ?
    auto is_dot = [](char c) {
      return '.' == c;
    };

    bool ul = is_dot(cs[i][j]);
    bool ur = is_dot(cs[i][j + 1]);
    bool dl = is_dot(cs[i + 1][j]);
    bool dr = is_dot(cs[i + 1][j + 1]);

    // split pattern:
    // #.    .#
    // .. or ##
    if ((ul != ur) and (ur == dl) and (dl == dr)) {
      pts.emplace_back(point(h - i, j), -1);
    }

    // merge pattern:
    // ..    ##
    // .# or #.
    if (ul == ur and ur == dl and dl != dr) {
      pts.emplace_back(point(h - i, j), 1);
    }
  }

  pts.emplace_back(point(-1, -1), 0);

  auto cmp = [](pair<point, int> &a, pair<point, int> &b) {
    return intgeometry2d::argcmp(a.first, b.first);
  };
  whole(sort, pts, cmp);

  int ans = 1;
  int cnt = 2;
  range(i, 1, pts.size()) {
    point pre = pts[i - 1].first;
    point pt = pts[i].first;
    if (intgeometry2d::det(pre, pt)) {
      chmax(ans, cnt);
    }

    cnt += pts[i].second;
  }

  cout << ans << endl;
}

signed main() {
  solve();
}
accuracy: 1
time_ms: 10
memory_kb: 5156
final_rank: 2

code_snippet: #include <bits/extc++.h>

using namespace std;

#define rep(i,n) for(int i=0;i<(n);++i)
#define reps(i,s,n) for(int i=(s);i<=(n);++i)
#define all(x) begin(x), end(x)
#define Fixed fixed << setprecision(12)
#define int int64_t
using pii = pair<int,int>;
constexpr int32_t INF  = 0x3f3f3f3f;
constexpr int64_t LINF = 0x3f3f3f3f3f3f3f3fLL;
constexpr int mod1 = 1e9+7;
constexpr int mod2 = 998244353;

template <class Func>
class FixPoint : Func {
public:
    explicit constexpr FixPoint(Func&& f) noexcept : Func(forward<Func>(f)) {}

    template <class... Args>
    constexpr decltype(auto) operator()(Args&&... args) const {
        return Func::operator()(*this, std::forward<Args>(args)...);
    }
};

template <class Func>
static inline constexpr decltype(auto) makeFixPoint(Func&& f) noexcept {
    return FixPoint<Func>{forward<Func>(f)};
}

template <class A, class B> inline bool chmax(A &a, const B &b) { return b > a && (a = b, true); }
template <class A, class B> inline bool chmin(A &a, const B &b) { return b < a && (a = b, true); }

template <class T> using max_heap = priority_queue<T>;
template <class T> using min_heap = priority_queue<T,vector<T>,greater<T> >;
template <class A, class B> using umap = unordered_map<A,B>;

template <class T> using Set = __gnu_pbds::tree<T, __gnu_pbds::null_type, less<T>, __gnu_pbds::rb_tree_tag, __gnu_pbds::tree_order_statistics_node_update>;

template <class T> inline void bye(T x) { cout << x << '\n'; exit(0); }

inline int updiv(int a,int b){ return (a + b - 1) / b; }

constexpr int dx[] = {1,0,-1,0,1,1,-1,-1};
constexpr int dy[] = {0,-1,0,1,1,-1,-1,1};


signed main() {
    cin.tie(nullptr);
    ios_base::sync_with_stdio(false);

    int h, w;
    cin >> h >> w;

    vector<string> mat(h);

    for (int i = 0; i < h; ++i) cin >> mat[i];
    reverse(all(mat));

    vector<pair<int, int> > points;

    auto inside = [&](int y, int x) {
        return (0 <= y && y < h && 0 <= x && x < w);
    };

    for (int i = 0; i < h; ++i) {
        for (int j = 0; j < w; ++j) {
            if (mat[i][j] != '#') continue;
            for (int k = 4; k < 8; ++k) {
                vector<bool> flg(4);
                int y = i + dy[k], x = j + dx[k];
                if (inside(y, x) && mat[y][x] != '.') continue;
                if (y == -1 && x == -1) continue;
                // cout << i << ' ' << j << " : " << y << ' ' << x << '\n';
                for (int s = 0; s < 4; ++s) {
                    int ty = y + dy[s], tx = x + dx[s];
                    if (inside(ty, tx) && mat[ty][tx] == '#') {
                        flg[s] = true;
                    }
                }
                if (k == 4) {
                    if (flg[1] == flg[2]) points.emplace_back(i + 1, j + 1);
                } else if (k == 5) {
                    if (flg[3] == flg[2]) points.emplace_back(i, j + 1);
                } else if (k == 6) {
                    if (flg[0] == flg[3]) points.emplace_back(i, j);
                } else {
                    if (flg[0] == flg[1]) points.emplace_back(i + 1, j);
                }
            }
        }
    }

    sort(all(points), [](const auto &a, const auto &b) -> bool {
        return (atan2l(a.first, a.second) < atan2l(b.first, b.second));
    });

    points.erase(unique(all(points)), points.end());

    // for (auto [y, x] : points) {
    //     cout << y << ' ' << x << ' ' << atan2l(y, x) << '\n';
    // }

    vector<vector<pair<int, int> > > points2;

    for (auto [y, x] : points) {
        if (points2.empty() || atan2l(points2.back().back().first, points2.back().back().second) != atan2l(y, x)) {
            points2.emplace_back(vector<pair<int, int> >(1, make_pair(y, x)));
        } else {
            points2.back().emplace_back(y, x);
        }
    }

    for (auto &v : points2) {
        sort(all(v), [](const auto &a, const auto &b) {
            return (a.second != b.second ? a.second < b.second : a.first < b.first);
        });
    }

    auto Tile = [&](int y, int x) {
        return !(!inside(y, x) || mat[y][x] == '.');
    };
    auto Type = [&](int y, int x) {
        if (Tile(y - 1, x - 1)) {
            if (Tile(y - 1, x) && Tile(y, x - 1)) return (0);
            if (!Tile(y - 1, x) && !Tile(y, x - 1)) return (1);
        }
        if (Tile(y, x - 1)) {
            if (Tile(y, x) && Tile(y - 1, x - 1)) return (2);
            if (!Tile(y, x) && !Tile(y - 1, x - 1)) return (3);
        }
        if (Tile(y, x)) {
            if (Tile(y, x - 1) && Tile(y - 1, x)) return (4);
            if (!Tile(y, x - 1) && !Tile(y - 1, x)) return (5);
        }
        if (Tile(y - 1, x)) {
            if (Tile(y, x) && Tile(y - 1, x - 1)) return (6);  
            if (!Tile(y, x) && !Tile(y - 1, x - 1)) return (7);
        }
        return (-1);
    };

    int sz = points2.size(), cnt = 0, res = 0;
    for (int i = 0; i < sz - 1; ++i) {
        for (auto [y, x] : points2[i]) {
            // cout << y << ' ' << x << '\n';
            switch (Type(y, x)) {
                case 0:
                    break;
                case 1:
                    break;
                case 2:
                    cnt -= 2;
                    break;
                case 3:
                    cnt += 2;
                    break;
                case 4:
                    break;
                case 5:
                    break;
                case 6:
                    cnt += 2;
                    break;
                case 7:
                    cnt -= 2;
                    break;
                default:
                    // cout << "Error\n";
                    break;
            }
        }
        // cout << "-----\n>";
        // cout << cnt << '\n';
        // cout << "-----\n";
        chmax(res, cnt);
    }

    cout << res / 2 + 1 << '\n';

    return(0);
}
accuracy: 1
time_ms: 300
memory_kb: 12912
final_rank: 19

code_snippet: #include <bits/extc++.h>

using namespace std;

#define rep(i,n) for(int i=0;i<(n);++i)
#define reps(i,s,n) for(int i=(s);i<=(n);++i)
#define all(x) begin(x), end(x)
#define Fixed fixed << setprecision(12)
#define int int64_t
using pii = pair<int,int>;
constexpr int32_t INF  = 0x3f3f3f3f;
constexpr int64_t LINF = 0x3f3f3f3f3f3f3f3fLL;
constexpr int mod1 = 1e9+7;
constexpr int mod2 = 998244353;

template <class Func>
class FixPoint : Func {
public:
    explicit constexpr FixPoint(Func&& f) noexcept : Func(forward<Func>(f)) {}

    template <class... Args>
    constexpr decltype(auto) operator()(Args&&... args) const {
        return Func::operator()(*this, std::forward<Args>(args)...);
    }
};

template <class Func>
static inline constexpr decltype(auto) makeFixPoint(Func&& f) noexcept {
    return FixPoint<Func>{forward<Func>(f)};
}

template <class A, class B> inline bool chmax(A &a, const B &b) { return b > a && (a = b, true); }
template <class A, class B> inline bool chmin(A &a, const B &b) { return b < a && (a = b, true); }

template <class T> using max_heap = priority_queue<T>;
template <class T> using min_heap = priority_queue<T,vector<T>,greater<T> >;
template <class A, class B> using umap = unordered_map<A,B>;

template <class T> using Set = __gnu_pbds::tree<T, __gnu_pbds::null_type, less<T>, __gnu_pbds::rb_tree_tag, __gnu_pbds::tree_order_statistics_node_update>;

template <class T> inline void bye(T x) { cout << x << '\n'; exit(0); }

inline int updiv(int a,int b){ return (a + b - 1) / b; }

constexpr int dx[] = {1,0,-1,0,1,1,-1,-1};
constexpr int dy[] = {0,-1,0,1,1,-1,-1,1};


signed main() {
    cin.tie(nullptr);
    ios_base::sync_with_stdio(false);

    int h, w;
    cin >> h >> w;

    vector<string> mat(h);

    for (int i = 0; i < h; ++i) cin >> mat[i];
    reverse(all(mat));

    vector<pair<int, int> > points;

    auto inside = [&](int y, int x) {
        return (0 <= y && y < h && 0 <= x && x < w);
    };

    for (int i = 0; i < h; ++i) {
        for (int j = 0; j < w; ++j) {
            if (mat[i][j] != '#') continue;
            for (int k = 4; k < 8; ++k) {
                vector<bool> flg(4);
                int y = i + dy[k], x = j + dx[k];
                if (inside(y, x) && mat[y][x] != '.') continue;
                if (y == -1 && x == -1) continue;
                // cout << i << ' ' << j << " : " << y << ' ' << x << '\n';
                for (int s = 0; s < 4; ++s) {
                    int ty = y + dy[s], tx = x + dx[s];
                    if (inside(ty, tx) && mat[ty][tx] == '#') {
                        flg[s] = true;
                    }
                }
                if (k == 4) {
                    if (flg[1] == flg[2]) points.emplace_back(i + 1, j + 1);
                } else if (k == 5) {
                    if (flg[3] == flg[2]) points.emplace_back(i, j + 1);
                } else if (k == 6) {
                    if (flg[0] == flg[3]) points.emplace_back(i, j);
                } else {
                    if (flg[0] == flg[1]) points.emplace_back(i + 1, j);
                }
            }
        }
    }

    sort(all(points), [](const auto &a, const auto &b) -> bool {
        return (atan2l(a.first, a.second) < atan2l(b.first, b.second));
    });

    points.erase(unique(all(points)), points.end());

    // for (auto [y, x] : points) {
    //     cout << y << ' ' << x << ' ' << atan2l(y, x) << '\n';
    // }

    vector<vector<pair<int, int> > > points2;

    for (auto [y, x] : points) {
        if (points2.empty() || atan2l(points2.back().back().first, points2.back().back().second) != atan2l(y, x)) {
            points2.emplace_back(vector<pair<int, int> >(1, make_pair(y, x)));
        } else {
            points2.back().emplace_back(y, x);
        }
    }

    for (auto &v : points2) {
        sort(all(v), [](const auto &a, const auto &b) {
            return (a.second != b.second ? a.second < b.second : a.first < b.first);
        });
    }

    auto Tile = [&](int y, int x) {
        return !(!inside(y, x) || mat[y][x] == '.');
    };
    auto Type = [&](int y, int x) {
        if (Tile(y - 1, x - 1)) {
            if (Tile(y - 1, x) && Tile(y, x - 1)) return (0);
            if (!Tile(y - 1, x) && !Tile(y, x - 1)) return (1);
        }
        if (Tile(y, x - 1)) {
            if (Tile(y, x) && Tile(y - 1, x - 1)) return (2);
            if (!Tile(y, x) && !Tile(y - 1, x - 1)) return (3);
        }
        if (Tile(y, x)) {
            if (Tile(y, x - 1) && Tile(y - 1, x)) return (4);
            if (!Tile(y, x - 1) && !Tile(y - 1, x)) return (5);
        }
        if (Tile(y - 1, x)) {
            if (Tile(y, x) && Tile(y - 1, x - 1)) return (6);  
            if (!Tile(y, x) && !Tile(y - 1, x - 1)) return (7);
        }
        return (-1);
    };

    int sz = points2.size(), cnt = 0, res = 0;
    for (int i = 0; i < sz - 1; ++i) {
        for (auto [y, x] : points2[i]) {
            // cout << y << ' ' << x << '\n';
            switch (Type(y, x)) {
                case 0:
                    break;
                case 1:
                    break;
                case 2:
                    cnt -= 2;
                    break;
                case 3:
                    cnt += 2;
                    break;
                case 4:
                    break;
                case 5:
                    break;
                case 6:
                    cnt += 2;
                    break;
                case 7:
                    cnt -= 2;
                    break;
                default:
                    // cout << "Error\n";
                    break;
            }
        }
        // cout << "-----\n>";
        // cout << cnt << '\n';
        // cout << "-----\n";
        chmax(res, cnt);
    }

    cout << res / 2 + 1 << '\n';

    return(0);
}
accuracy: 1
time_ms: 300
memory_kb: 13512
final_rank: 20

code_snippet: #include<bits/stdc++.h>
#define int ll
#define rep(i, N) for(int i = 0; i < (int)N; ++i)
#define rep1(i, N) for(int i = 1; i <= (int)N; ++i)
#define per(i, N) for(int i = N-1; i >= 0; --i)
#define per1(i, N) for(int i = N; i >= 1; --i)
#define FOR(i, f, t) for(int i = f; i < (int)t; ++i)
#define all(v) (v).begin(), (v).end()
#define rall(v) (v).rbegin(), (v).rend()
#define bit(n) (1ll << (n))
#define pcnt(n) (__builtin_popcount(n))
#define TakAo(ans) ans ? cout << "Takahashi\n" : cout << "Aoki\n"
#define YesNo(ans) ans ? cout << "Yes\n" : cout << "No\n"
#define endl '\n'
#define fi first
#define se second
#define mkpr make_pair
#define mktpl make_tuple
#define eb emplace_back

using namespace std;
using ll = int64_t;
using ull = uint64_t;
using ld = long double;
using point = struct{ ll x, y; };
template<class T> using max_heap = priority_queue<T>;
template<class T> using min_heap = priority_queue<T, vector<T>, greater<T>>;
template<class T> using vec = vector<T>;
template<class T> using vvec = vec<vec<T>>;
template<class T> using vvvec = vec<vec<vec<T>>>;
template<class T> using vvvvec = vec<vec<vec<vec<T>>>>;

constexpr ld EPS = 1e-10;
constexpr int INF = 1001001001;
constexpr ll LINF = 1001001001001001001ll;
constexpr int MOD = 1e9+7;
//constexpr ll MOD = 998244353;
constexpr int div2 = (MOD + 1) >> 1;
constexpr int NIL = -1;
constexpr int pm[2] = {1, -1};
constexpr int dy[4] = {0, 1, 0, -1};
constexpr int dx[4] = {1, 0, -1, 0};

ll cel(ll a, ll b){ return (a + b - 1) / b;}
ll Gcd(ll a, ll b){ return b ? Gcd(b, a % b) : a;}
template<class T> T powi(T x, ll exp){
    return exp > 0 ? (exp & 1 ? x : 1) * powi(x * x, exp >> 1) : 1;
}
ll modpow(ll x, ll exp, ll mod){
    x %= mod;
    return exp > 0 ? (exp & 1 ? x : 1) * modpow(x * x, exp >> 1, mod) % mod : 1;
}
template<class T> bool chmin(T &a, T b){ return a > b ? (a = b, true) : 0;}
template<class T> bool chmax(T &a, T b){ return a < b ? (a = b, true) : 0;}

using P = pair<ll, ll>;
using Tpl = tuple<int, int, int, int>;

bool comp(pair<point, ll> &a, pair<point, ll> &b){
    return a.fi.x * b.fi.y < a.fi.y * b.fi.x;
}

bool eq(pair<point, ll> &a, pair<point, ll> &b){
    return a.fi.x * b.fi.y == a.fi.y * b.fi.x;
}

void Main(){
    int H, W; cin >> H >> W;
    vvec<char> G(H + 10, vec<char>(W + 10, '.'));
    rep(i, H){
        rep(j, W) cin >> G[i + 1][j + 1];
    }
    vec<pair<point, ll>> XY;

    rep(i, H){
         rep(j, W){
            if(G[i + 1][j + 1] == '#'){
                if(G[i][j] == '.' && G[i + 1][j] == '.' && G[i][j + 1] == '.'){
                    XY.eb(mkpr(point{j, H - i}, 1));
                }
            }
            else{
                if(G[i][j] == '#' && G[i + 1][j] == '#' && G[i][j + 1] == '#'){
                    XY.eb(mkpr(point{j, H - i}, 1));
                }
            }
        }
    }
    rep(i, H){
        rep(j, W){
            if(G[i + 1][j + 1] == '#'){
                if(G[i + 2][j + 2] == '.' && G[i + 2][j + 1] == '.' && G[i + 1][j + 2] == '.'){
                    XY.eb(mkpr(point{j + 1, H - i - 1}, -1));
                }
            }
            else{
                if(G[i + 2][j + 2] == '#' && G[i + 2][j + 1] == '#' && G[i + 1][j + 2] == '#'){
                    XY.eb(mkpr(point{j + 1, H - i - 1}, -1));
                }
            }
        }
    }
    if(int(XY.size()) == 0){
        cout << 0 << endl;
        return;
    }

    sort(all(XY), comp);

    /* 
    for(auto it : XY){
        cout << it.fi.x << " " << it.fi.y << " " << it.se << endl;
    }
    */
        
    int M = int(XY.size());
    pair<point, ll> prev = XY[0];
    int cnt = 2;
    int ans = 0;
    rep(i, M){
        if(i == 0) continue;
        if(eq(XY[i], prev)){
            cnt += XY[i].se;
            prev = XY[i];
        }
        else{
            chmax(ans, cnt);
            //cout << cnt << endl;
            cnt += XY[i].se;
            prev = XY[i];
        }
    }
    cout << ans << endl;
}

signed main(){
    cin.tie(nullptr);
    ios_base::sync_with_stdio(false);
    cout << fixed << setprecision(10);
    Main();
    return 0;
}
accuracy: 1
time_ms: 10
memory_kb: 7868
final_rank: 8

code_snippet: #include<bits/stdc++.h>
#define int ll
#define rep(i, N) for(int i = 0; i < (int)N; ++i)
#define rep1(i, N) for(int i = 1; i <= (int)N; ++i)
#define per(i, N) for(int i = N-1; i >= 0; --i)
#define per1(i, N) for(int i = N; i >= 1; --i)
#define FOR(i, f, t) for(int i = f; i < (int)t; ++i)
#define all(v) (v).begin(), (v).end()
#define rall(v) (v).rbegin(), (v).rend()
#define bit(n) (1ll << (n))
#define pcnt(n) (__builtin_popcount(n))
#define TakAo(ans) ans ? cout << "Takahashi\n" : cout << "Aoki\n"
#define YesNo(ans) ans ? cout << "Yes\n" : cout << "No\n"
#define endl '\n'
#define fi first
#define se second
#define mkpr make_pair
#define mktpl make_tuple
#define eb emplace_back

using namespace std;
using ll = int64_t;
using ull = uint64_t;
using ld = long double;
using point = struct{ ll x, y; };
template<class T> using max_heap = priority_queue<T>;
template<class T> using min_heap = priority_queue<T, vector<T>, greater<T>>;
template<class T> using vec = vector<T>;
template<class T> using vvec = vec<vec<T>>;
template<class T> using vvvec = vec<vec<vec<T>>>;
template<class T> using vvvvec = vec<vec<vec<vec<T>>>>;

constexpr ld EPS = 1e-10;
constexpr int INF = 1001001001;
constexpr ll LINF = 1001001001001001001ll;
constexpr int MOD = 1e9+7;
//constexpr ll MOD = 998244353;
constexpr int div2 = (MOD + 1) >> 1;
constexpr int NIL = -1;
constexpr int pm[2] = {1, -1};
constexpr int dy[4] = {0, 1, 0, -1};
constexpr int dx[4] = {1, 0, -1, 0};

ll cel(ll a, ll b){ return (a + b - 1) / b;}
ll Gcd(ll a, ll b){ return b ? Gcd(b, a % b) : a;}
template<class T> T powi(T x, ll exp){
    return exp > 0 ? (exp & 1 ? x : 1) * powi(x * x, exp >> 1) : 1;
}
ll modpow(ll x, ll exp, ll mod){
    x %= mod;
    return exp > 0 ? (exp & 1 ? x : 1) * modpow(x * x, exp >> 1, mod) % mod : 1;
}
template<class T> bool chmin(T &a, T b){ return a > b ? (a = b, true) : 0;}
template<class T> bool chmax(T &a, T b){ return a < b ? (a = b, true) : 0;}

using P = pair<ll, ll>;
using Tpl = tuple<int, int, int, int>;

bool comp(pair<point, ll> &a, pair<point, ll> &b){
    return a.fi.x * b.fi.y < a.fi.y * b.fi.x;
}

bool eq(pair<point, ll> &a, pair<point, ll> &b){
    return a.fi.x * b.fi.y == a.fi.y * b.fi.x;
}

void Main(){
    int H, W; cin >> H >> W;
    vvec<char> G(H + 10, vec<char>(W + 10, '.'));
    rep(i, H){
        rep(j, W) cin >> G[i + 1][j + 1];
    }
    vec<pair<point, ll>> XY;

    rep(i, H){
         rep(j, W){
            if(G[i + 1][j + 1] == '#'){
                if(G[i][j] == '.' && G[i + 1][j] == '.' && G[i][j + 1] == '.'){
                    XY.eb(mkpr(point{j, H - i}, 1));
                }
            }
            else{
                if(G[i][j] == '#' && G[i + 1][j] == '#' && G[i][j + 1] == '#'){
                    XY.eb(mkpr(point{j, H - i}, 1));
                }
            }
        }
    }
    rep(I, H){
        rep(j, W){
            if(G[I + 1][j + 1] == '#'){
                if(G[I + 2][j + 2] == '.' && G[I + 2][j + 1] == '.' && G[I + 1][j + 2] == '.'){
                    XY.eb(mkpr(point{j + 1, H - I - 1}, -1));
                }
            }
            else{
                if(G[I + 2][j + 2] == '#' && G[I + 2][j + 1] == '#' && G[I + 1][j + 2] == '#'){
                    XY.eb(mkpr(point{j + 1, H - I - 1}, -1));
                }
            }
        }
    }
    if(int(XY.size()) == 0){
        cout << 0 << endl;
        return;
    }

    sort(all(XY), comp);

    /* 
    for(auto it : XY){
        cout << it.fi.x << " " << it.fi.y << " " << it.se << endl;
    }
    */
        
    int M = int(XY.size());
    pair<point, ll> prev = XY[0];
    int cnt = 2;
    int ans = 0;
    rep(i, M){
        if(i == 0) continue;
        if(eq(XY[i], prev)){
            cnt += XY[i].se;
            prev = XY[i];
        }
        else{
            chmax(ans, cnt);
            //cout << cnt << endl;
            cnt += XY[i].se;
            prev = XY[i];
        }
    }
    cout << ans << endl;
}

signed main(){
    cin.tie(nullptr);
    ios_base::sync_with_stdio(false);
    cout << fixed << setprecision(10);
    Main();
    return 0;
}
accuracy: 1
time_ms: 10
memory_kb: 7980
final_rank: 9

code_snippet: #include<bits/stdc++.h>
#define int ll
#define rep(i, N) for(int i = 0; i < (int)N; ++i)
#define rep1(i, N) for(int i = 1; i <= (int)N; ++i)
#define per(i, N) for(int i = N-1; i >= 0; --i)
#define per1(i, N) for(int i = N; i >= 1; --i)
#define FOR(i, f, t) for(int i = f; i < (int)t; ++i)
#define all(v) (v).begin(), (v).end()
#define rall(v) (v).rbegin(), (v).rend()
#define bit(n) (1ll << (n))
#define pcnt(n) (__builtin_popcount(n))
#define TakAo(ans) ans ? cout << "Takahashi\n" : cout << "Aoki\n"
#define YesNo(ans) ans ? cout << "Yes\n" : cout << "No\n"
#define endl '\n'
#define fi first
#define se second
#define mkpr make_pair
#define mktpl make_tuple
#define eb emplace_back

using namespace std;
using ll = int64_t;
using ull = uint64_t;
using ld = long double;
using point = struct{ ll x, y; };
template<class T> using max_heap = priority_queue<T>;
template<class T> using min_heap = priority_queue<T, vector<T>, greater<T>>;
template<class T> using vec = vector<T>;
template<class T> using vvec = vec<vec<T>>;
template<class T> using vvvec = vec<vec<vec<T>>>;
template<class T> using vvvvec = vec<vec<vec<vec<T>>>>;

constexpr ld EPS = 1e-10;
constexpr int INF = 1001001001;
constexpr ll LINF = 1001001001001001001ll;
constexpr int MOD = 1e9+7;
//constexpr ll MOD = 998244353;
constexpr int div2 = (MOD + 1) >> 1;
constexpr int NIL = -1;
constexpr int pm[2] = {1, -1};
constexpr int dy[4] = {0, 1, 0, -1};
constexpr int dx[4] = {1, 0, -1, 0};

ll cel(ll a, ll b){ return (a + b - 1) / b;}
ll Gcd(ll a, ll b){ return b ? Gcd(b, a % b) : a;}
template<class T> T powi(T x, ll exp){
    return exp > 0 ? (exp & 1 ? x : 1) * powi(x * x, exp >> 1) : 1;
}
ll modpow(ll x, ll exp, ll mod){
    x %= mod;
    return exp > 0 ? (exp & 1 ? x : 1) * modpow(x * x, exp >> 1, mod) % mod : 1;
}
template<class T> bool chmin(T &a, T b){ return a > b ? (a = b, true) : 0;}
template<class T> bool chmax(T &a, T b){ return a < b ? (a = b, true) : 0;}

using P = pair<ll, ll>;
using Tpl = tuple<int, int, int, int>;

bool comp(pair<point, ll> &a, pair<point, ll> &b){
    return a.fi.x * b.fi.y < a.fi.y * b.fi.x;
}

bool eq(pair<point, ll> &a, pair<point, ll> &b){
    return a.fi.x * b.fi.y == a.fi.y * b.fi.x;
}

void Main(){
    int H, W; cin >> H >> W;
    vvec<char> G(H + 700, vec<char>(W + 700, '.'));
    rep(i, H){
        rep(j, W) cin >> G[i + 1][j + 1];
    }
    vec<pair<point, ll>> XY;

    rep(i, H){
         rep(j, W){
            if(G[i + 1][j + 1] == '#'){
                if(G[i][j] == '.' && G[i + 1][j] == '.' && G[i][j + 1] == '.'){
                    XY.eb(mkpr(point{j, H - i}, 1));
                }
            }
            else{
                if(G[i][j] == '#' && G[i + 1][j] == '#' && G[i][j + 1] == '#'){
                    XY.eb(mkpr(point{j, H - i}, 1));
                }
            }
        }
    }
    rep(I, H){
        rep(j, W){
            if(G[I + 1][j + 1] == '#'){
                if(G[I + 2][j + 2] == '.' && G[I + 2][j + 1] == '.' && G[I + 1][j + 2] == '.'){
                    XY.eb(mkpr(point{j + 1, H - I - 1}, -1));
                }
            }
            else{
                if(G[I + 2][j + 2] == '#' && G[I + 2][j + 1] == '#' && G[I + 1][j + 2] == '#'){
                    XY.eb(mkpr(point{j + 1, H - I - 1}, -1));
                }
            }
        }
    }
    if(int(XY.size()) == 0){
        cout << 0 << endl;
        return;
    }

    sort(all(XY), comp);

    /* 
    for(auto it : XY){
        cout << it.fi.x << " " << it.fi.y << " " << it.se << endl;
    }
    */
        
    int M = int(XY.size());
    pair<point, ll> prev = XY[0];
    int cnt = 2;
    int ans = 0;
    rep(i, M){
        if(i == 0) continue;
        if(eq(XY[i], prev)){
            cnt += XY[i].se;
            prev = XY[i];
        }
        else{
            chmax(ans, cnt);
            //cout << cnt << endl;
            cnt += XY[i].se;
            prev = XY[i];
        }
    }
    cout << ans << endl;
}

signed main(){
    cin.tie(nullptr);
    ios_base::sync_with_stdio(false);
    cout << fixed << setprecision(10);
    Main();
    return 0;
}
accuracy: 1
time_ms: 10
memory_kb: 8656
final_rank: 11

code_snippet: #include<bits/stdc++.h>
#define int ll
#define rep(i, N) for(int i = 0; i < (int)N; ++i)
#define rep1(i, N) for(int i = 1; i <= (int)N; ++i)
#define per(i, N) for(int i = N-1; i >= 0; --i)
#define per1(i, N) for(int i = N; i >= 1; --i)
#define FOR(i, f, t) for(int i = f; i < (int)t; ++i)
#define all(v) (v).begin(), (v).end()
#define rall(v) (v).rbegin(), (v).rend()
#define bit(n) (1ll << (n))
#define pcnt(n) (__builtin_popcount(n))
#define TakAo(ans) ans ? cout << "Takahashi\n" : cout << "Aoki\n"
#define YesNo(ans) ans ? cout << "Yes\n" : cout << "No\n"
#define endl '\n'
#define fi first
#define se second
#define mkpr make_pair
#define mktpl make_tuple
#define eb emplace_back

using namespace std;
using ll = int64_t;
using ull = uint64_t;
using ld = long double;
using point = struct{ ll x, y; };
template<class T> using max_heap = priority_queue<T>;
template<class T> using min_heap = priority_queue<T, vector<T>, greater<T>>;
template<class T> using vec = vector<T>;
template<class T> using vvec = vec<vec<T>>;
template<class T> using vvvec = vec<vec<vec<T>>>;
template<class T> using vvvvec = vec<vec<vec<vec<T>>>>;

constexpr ld EPS = 1e-10;
constexpr int INF = 1001001001;
constexpr ll LINF = 1001001001001001001ll;
constexpr int MOD = 1e9+7;
//constexpr ll MOD = 998244353;
constexpr int div2 = (MOD + 1) >> 1;
constexpr int NIL = -1;
constexpr int pm[2] = {1, -1};
constexpr int dy[4] = {0, 1, 0, -1};
constexpr int dx[4] = {1, 0, -1, 0};

ll cel(ll a, ll b){ return (a + b - 1) / b;}
ll Gcd(ll a, ll b){ return b ? Gcd(b, a % b) : a;}
template<class T> T powi(T x, ll exp){
    return exp > 0 ? (exp & 1 ? x : 1) * powi(x * x, exp >> 1) : 1;
}
ll modpow(ll x, ll exp, ll mod){
    x %= mod;
    return exp > 0 ? (exp & 1 ? x : 1) * modpow(x * x, exp >> 1, mod) % mod : 1;
}
template<class T> bool chmin(T &a, T b){ return a > b ? (a = b, true) : 0;}
template<class T> bool chmax(T &a, T b){ return a < b ? (a = b, true) : 0;}

using P = pair<ll, ll>;
using Tpl = tuple<int, int, int, int>;

bool comp(const pair<point, ll> &a, const pair<point, ll> &b){
    return a.fi.x * b.fi.y < a.fi.y * b.fi.x;
}

bool eq(const pair<point, ll> &a, const pair<point, ll> &b){
    return a.fi.x * b.fi.y == a.fi.y * b.fi.x;
}

void Main(){
    int H, W; cin >> H >> W;
    vvec<char> G(H + 700, vec<char>(W + 700, '.'));
    rep(i, H){
        rep(j, W) cin >> G[i + 1][j + 1];
    }
    vec<pair<point, ll>> XY;

    rep(i, H){
         rep(j, W){
            if(G[i + 1][j + 1] == '#'){
                if(G[i][j] == '.' && G[i + 1][j] == '.' && G[i][j + 1] == '.'){
                    XY.eb(mkpr(point{j, H - i}, 1));
                }
            }
            else{
                if(G[i][j] == '#' && G[i + 1][j] == '#' && G[i][j + 1] == '#'){
                    XY.eb(mkpr(point{j, H - i}, 1));
                }
            }
        }
    }
    rep(I, H){
        rep(j, W){
            if(G[I + 1][j + 1] == '#'){
                if(G[I + 2][j + 2] == '.' && G[I + 2][j + 1] == '.' && G[I + 1][j + 2] == '.'){
                    XY.eb(mkpr(point{j + 1, H - I - 1}, -1));
                }
            }
            else{
                if(G[I + 2][j + 2] == '#' && G[I + 2][j + 1] == '#' && G[I + 1][j + 2] == '#'){
                    XY.eb(mkpr(point{j + 1, H - I - 1}, -1));
                }
            }
        }
    }
    if(int(XY.size()) == 0){
        cout << 0 << endl;
        return;
    }

    sort(all(XY), comp);

    /* 
    for(auto it : XY){
        cout << it.fi.x << " " << it.fi.y << " " << it.se << endl;
    }
    */
        
    int M = int(XY.size());
    pair<point, ll> prev = XY[0];
    int cnt = 2;
    int ans = 0;
    rep(i, M){
        if(i == 0) continue;
        if(eq(XY[i], prev)){
            cnt += XY[i].se;
            prev = XY[i];
        }
        else{
            chmax(ans, cnt);
            //cout << cnt << endl;
            cnt += XY[i].se;
            prev = XY[i];
        }
    }
    cout << ans << endl;
}

signed main(){
    cin.tie(nullptr);
    ios_base::sync_with_stdio(false);
    cout << fixed << setprecision(10);
    Main();
    return 0;
}
accuracy: 1
time_ms: 10
memory_kb: 9460
final_rank: 15

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

typedef string::const_iterator State;
#define eps 1e-8L
#define MAX_MOD 1000000007LL
#define GYAKU 500000004LL
#define MOD 998244353LL
#define pb push_back
#define mp make_pair
typedef long long ll;
typedef long double ld;
#define REP(a, b) for (long long(a) = 0; (a) < (b); ++(a))
#define ALL(x) (x).begin(), (x).end()

#define int long long
void solve(){
  int h, w;
  cin >> h >> w;
  vector<string> inputs;
  inputs.push_back(string(w + 2, '.'));
  REP(i, h)
  {
    string s;
    cin >> s;
    s = "." + s + ".";
    inputs.push_back(s);
  }
  inputs.push_back(string(w + 2, '.'));
  vector<pair<double, int>> cnter;
  REP(i, h + 1)
  {
    REP(q, w + 1)
    {
      double ang = atan2(h - i, q); 
      if(inputs[i][q] =='#' and inputs[i+1][q] == '.' and inputs[i][q+1] == '.' and inputs[i+1][q+1] == '.'){
        cnter.push_back({ang, 1});
      }
      if(inputs[i][q] =='.' and inputs[i+1][q] == '.' and inputs[i][q+1] == '.' and inputs[i+1][q+1] == '#'){
        cnter.push_back({ang, -1});
      }
      if(inputs[i][q] =='.' and inputs[i+1][q] == '#' and inputs[i][q+1] == '#' and inputs[i+1][q+1] == '#'){
        cnter.push_back({ang, 1});
      }
      if(inputs[i][q] =='#' and inputs[i+1][q] == '#' and inputs[i][q+1] == '#' and inputs[i+1][q+1] == '.'){
        cnter.push_back({ang, -1});
      }
    }
  }
  sort(ALL(cnter));
  int cur = 1;
  int ans = 2;
  for(auto x:cnter){
    cur += x.second;
    ans = max(ans, cur);
  }
  cout << ans << endl;
}
#undef int

// generated by oj-template v4.7.2
// (https://github.com/online-judge-tools/template-generator)
int main() {
  // Fasterize input/output script
  ios::sync_with_stdio(false);
  cin.tie(nullptr);
  cout << fixed << setprecision(100);
  // scanf/printf user should delete this fasterize input/output script

  int t = 1;
  //cin >> t; // comment out if solving multi testcase
  for (int testCase = 1; testCase <= t; ++testCase) {
    solve();
  }
  return 0;
}
accuracy: 1
time_ms: 10
memory_kb: 6060
final_rank: 6

code_snippet: #include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<vector>
#include<cmath>
#include<algorithm>
#include<map>
#include<queue>
#include<deque>
#include<iomanip>
#include<tuple>
#include<cassert>
#include<set>
#include<complex>
#include<numeric>
#include<functional>
#include<unordered_map>
#include<unordered_set>
using namespace std;
typedef long long int LL;
typedef pair<int,int> P;
typedef pair<LL,LL> LP;
const int INF=1<<30;
const LL MAX=1e9+7;

void array_show(int *array,int array_n,char middle=' '){
    for(int i=0;i<array_n;i++)printf("%d%c",array[i],(i!=array_n-1?middle:'\n'));
}
void array_show(LL *array,int array_n,char middle=' '){
    for(int i=0;i<array_n;i++)printf("%lld%c",array[i],(i!=array_n-1?middle:'\n'));
}
void array_show(vector<int> &vec_s,int vec_n=-1,char middle=' '){
    if(vec_n==-1)vec_n=vec_s.size();
    for(int i=0;i<vec_n;i++)printf("%d%c",vec_s[i],(i!=vec_n-1?middle:'\n'));
}
void array_show(vector<LL> &vec_s,int vec_n=-1,char middle=' '){
    if(vec_n==-1)vec_n=vec_s.size();
    for(int i=0;i<vec_n;i++)printf("%lld%c",vec_s[i],(i!=vec_n-1?middle:'\n'));
}
template<typename T> ostream& operator<<(ostream& os,const vector<T>& v1){
    int n=v1.size();
    for(int i=0;i<n;i++){
        if(i)os<<" ";
        os<<v1[i];
    }
    return os;
}
template<typename T1,typename T2> ostream& operator<<(ostream& os,const pair<T1,T2>& p){
    os<<p.first<<" "<<p.second;
    return os;
}
template<typename T> istream& operator>>(istream& is,vector<T>& v1){
    int n=v1.size();
    for(int i=0;i<n;i++)is>>v1[i];
    return is;
}
template<typename T1,typename T2> istream& operator>>(istream& is,pair<T1,T2>& p){
    is>>p.first>>p.second;
    return is;
}

class Fraction{
    typedef long long int ll;
    long long int gcd(long long int a,long long int b){
        if(a<b)swap(a,b);
        if(b==0)return a;
        return gcd(b,a%b);
    }

public:
    ll x,y;
    Fraction(){};
    Fraction(ll _x, ll _y):x(_x),y(_y){
        if(x==0 && y==0)return;
        if(y<0)x=-x,y=-y;
        ll d=gcd(abs(x),abs(y));
        x/=d,y/=d;
    }
    template<typename T> Fraction(pair<T,T> p){
        Fraction(p.first,p.second);
    }

    bool operator==(const Fraction f)const{
        return x==f.x && y==f.y;
    }
    bool operator<(const Fraction f)const{
        return x*f.y<f.x*y;
    }
    bool operator<=(const Fraction f)const{
        return x*f.y<=f.x*y;
    }
    bool operator>(const Fraction f)const{return !((*this)<=f);}
    bool operator>=(const Fraction f)const{return !((*this)<f);}
};

namespace sol{

    void solve(){
        int n,m;
        int i,j,k;
        int a,b,c;
        cin>>n>>m;
        vector<vector<char>> grid(n+2,vector<char>(m+2));
        string sa;
        for(i=0;i<n;i++){
            cin>>sa;
            for(j=0;j<m;j++){
                if(sa[j]=='#')grid[i+1][j+1]=1;
            }
        }
        vector<pair<Fraction,int>> v1;
        for(i=0;i<=n;i++){
            for(j=0;j<=m;j++){
                c=0;
                for(a=0;a<2;a++){
                    for(b=0;b<2;b++){
                        c+=grid[i+a][j+b];
                    }
                }
                if(c%2==0)continue;
                c=1-c/2;
                if(grid[i][j]==c)v1.push_back({Fraction(n-i,j),1});
                if(grid[i+1][j+1]==c)v1.push_back({Fraction(n-i,j),-1});
            }
        }
        sort(v1.begin(),v1.end());
        int s=0;
        int cnt=1;
        for(i=0;i<v1.size();i++){
            Fraction f=v1[i].first;
            a=v1[i].second;
            cnt+=a;
            if(i+1<v1.size() && f==v1[i+1].first)continue;
            s=max(s,cnt);
        }
        cout<<s<<endl;
    }
}

int main(){
    cin.tie(0);
    ios::sync_with_stdio(false);
    sol::solve();
}
accuracy: 1
time_ms: 10
memory_kb: 7752
final_rank: 7

code_snippet: #pragma GCC ta g("avx2")
#pragma GCC optimize("Ofast")
#pragma GCC optimize("unroll-loops")
#include <bits/stdc++.h>
using namespace std;
#define DEBUG
#ifdef DEBUG
template <class T, class U>
ostream &operator<<(ostream &os, const pair<T, U> &p) {
    os << '(' << p.first << ',' << p.second << ')';
    return os;
}
template <class T> ostream &operator<<(ostream &os, const vector<T> &v) {
    os << '{';
    for(int i = 0; i < (int)v.size(); i++) {
        if(i) { os << ','; }
        os << v[i];
    }
    os << '}';
    return os;
}
void debugg() { cerr << endl; }
template <class T, class... Args>
void debugg(const T &x, const Args &... args) {
    cerr << " " << x;
    debugg(args...);
}
#define debug(...)                                                             \
    cerr << __LINE__ << " [" << #__VA_ARGS__ << "]: ", debugg(__VA_ARGS__)
#define dump(x) cerr << __LINE__ << " " << #x << " = " << (x) << endl
#else
#define debug(...) (void(0))
#define dump(x) (void(0))
#endif
using namespace std;
typedef long long ll;
typedef vector<ll> vl;
typedef vector<vl> vvl;
typedef vector<char> vc;
typedef vector<string> vs;
typedef vector<bool> vb;
typedef vector<double> vd;
typedef pair<ll,ll> P;
typedef pair<int,int> pii;
typedef vector<P> vpl;
typedef tuple<ll,ll,ll> tapu;
#define rep(i,n) for(int i=0; i<(n); i++)
#define REP(i,a,b) for(int i=(a); i<(b); i++)
#define all(x) (x).begin(), (x).end()
#define rall(x) (x).rbegin(), (x).rend()
template<typename T1,typename T2> inline bool chmin(T1 &a,T2 b){
	if(a>b){
		a = b; return true;
	}
	else return false;
}
template<typename T1,typename T2> inline bool chmax(T1 &a,T2 b){
	if(a<b){
		a = b; return true;
	}
	else return false;
}
template<typename T> inline void print(T &a){
    int sz = a.size();
    for(auto itr = a.begin(); itr != a.end(); itr++){
		cout << *itr;
        sz--;
        if(sz) cout << " ";
	}
    cout << "\n";
}
template<typename T1,typename T2> inline void print2(T1 a, T2 b){
	cout << a << " " << b << "\n";
}
template<typename T1,typename T2,typename T3> inline void print3(T1 a, T2 b, T3 c){
	cout << a << " " << b << " " << c << "\n";
}
void mark() {cout << "#" << "\n";}
ll pcount(ll x) {return __builtin_popcountll(x);}
//#include <atcoder/maxflow>
//using namespace atcoder;
const int inf = (1<<30)-1;
const ll linf = 1LL<<61;
const int MAX = 510000;
int dy[8] = {0,1,0,-1,1,-1,-1,1};
int dx[8] = {-1,0,1,0,1,-1,1,-1};
const double pi = acos(-1);
const double eps = 1e-9;
//const int mod = 1e9 + 7;
const int mod = 998244353;

int main(){
	int h,w; cin >> h >> w;
	vs s(h); rep(i,h) cin >> s[i];
	rep(i,h) s[i].push_back('.');
	s.push_back(string(w+1,'.'));
	vector<pair<double,int>> ev;
	rep(i,h) rep(j,w){
		char a = s[i][j], b = s[i][j+1], c = s[i+1][j], d = s[i+1][j+1];
		if(a == b && b == c && a != d) ev.emplace_back((double)(h-i-1)/(j+1),-1);
		if(b == c && c == d && a != b) ev.emplace_back((double)(h-i-1)/(j+1),1);
	}
	rep(j,w-1) if(s[0][j] == '.' && s[0][j+1] == '#') ev.emplace_back((double)h/(j+1),-1);
	sort(all(ev));
	int now = 0, ans = 0, mn = 0;
	for(auto p : ev){
		now += p.second;
		chmin(mn,now);
		chmax(ans, now-mn);
	}
	cout << ans+1 << endl;
}
accuracy: 1
time_ms: 10
memory_kb: 5764
final_rank: 4

code_snippet: #pragma GCC optimize("Ofast")
#include <iostream>
#include <vector>
#include <algorithm>
#include <map>
#include <queue>
#include <cstdio>
#include <ctime>
#include <assert.h>
#include <chrono>
#include <random>
#include <numeric>
#include <set>
#include <deque>
#include <stack>
#include <sstream>
#include <utility>
#include <cstring>
#include <unordered_map>
#include <unordered_set>
#include <tuple>
#include <array>
using namespace std;
typedef long long int ll;
typedef unsigned long long 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<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<vector<char>> s(h+2,vector<char>(w+2,'.'));
    for(int i=0;i<h;i++){
        for(int j=0;j<w;j++){
            cin >> s[h-i][j+1];
        }
    }
    /*
    +1
    X. .X
    .. XX
    -1
    .. XX
    .X X.
    */
    vector<pair<pair<int,int>,int>> v;
    for(int i=0;i<=h;i++){
        for(int j=0;j<=w;j++){
            if(s[i][j] == '.' and s[i+1][j] == '#' and s[i][j+1] == '.' and s[i+1][j+1] == '.'){
                v.push_back({{i,j},1});
            }
            if(s[i][j] == '#' and s[i+1][j] == '.' and s[i][j+1] == '#' and s[i+1][j+1] == '#'){
                v.push_back({{i,j},1});
            }
            if(s[i][j] == '.' and s[i+1][j] == '.' and s[i][j+1] == '#' and s[i+1][j+1] == '.'){
                v.push_back({{i,j},-1});
            }
            if(s[i][j] == '#' and s[i+1][j] == '#' and s[i][j+1] == '.' and s[i+1][j+1] == '#'){
                v.push_back({{i,j},-1});
            }
        }
    }
    int res = 1;
    int cnt = 1;
    sort(v.begin(), v.end(), [&](auto i,auto j){
        int ix = i.first.second, iy = i.first.first;
        int jx = j.first.second, jy = j.first.first;
        // iy/ix < jy/jx
        if(iy*jx < jy*ix) return true;
        else if(iy*jx > jy*ix) return false;
        else{
            return i.second < j.second;
        }
    });
    for(int i=0;i<(int)v.size();i++){
        cnt += v[i].second;
        res = max(res, cnt);
    }
    cout << res << endl;
}
accuracy: 1
time_ms: 10
memory_kb: 5072
final_rank: 1

code_snippet: #include <bits/stdc++.h>
//#include <atcoder/all>
//using namespace atcoder;
#pragma GCC target ("avx2")
#pragma GCC optimization ("O3")
#pragma GCC optimization ("unroll-loops")
using namespace std;
 
typedef vector<int> VI;
typedef vector<VI> VVI;
typedef vector<string> VS;
typedef pair<int, int> PII;
typedef pair<int, int> pii;
typedef pair<long long, long long> PLL;
typedef pair<int, PII> TIII;
 
typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;
 
 
#define FOR(i, s, n) for (int i = s; i < (int)n; ++i)
#define REP(i, n) FOR(i, 0, n)
#define rep(i, a, b) for (int i = a; i < (b); ++i)
#define trav(a, x) for (auto &a : x)
#define all(x) x.begin(), x.end()
 
#define MOD 1000000007
 
template<class T1, class T2> inline bool chmax(T1 &a, T2 b) {if (a < b) {a = b; return true;} return false;}
template<class T1, class T2> inline bool chmin(T1 &a, T2 b) {if (a > b) {a = b; return true;} return false;}
const double EPS = 1e-8, PI = acos(-1);
const double pi = 3.141592653589793238462643383279;
//ここから編集    
typedef string::const_iterator State;
ll GCD(ll a, ll b){
  return (b==0)?a:GCD(b, a%b);
}
ll LCM(ll a, ll b){
  return a/GCD(a, b) * b;
}
template< int mod >
struct ModInt {
  int x;
 
  ModInt() : x(0) {}
 
  ModInt(int64_t y) : x(y >= 0 ? y % mod : (mod - (-y) % mod) % mod) {}
 
  ModInt &operator+=(const ModInt &p) {
    if((x += p.x) >= mod) x -= mod;
    return *this;
  }
 
  ModInt &operator-=(const ModInt &p) {
    if((x += mod - p.x) >= mod) x -= mod;
    return *this;
  }
 
  ModInt &operator*=(const ModInt &p) {
    x = (int) (1LL * x * p.x % mod);
    return *this;
  }
 
  ModInt &operator/=(const ModInt &p) {
    *this *= p.inverse();
    return *this;
  }
 
  ModInt operator-() const { return ModInt(-x); }
 
  ModInt operator+(const ModInt &p) const { return ModInt(*this) += p; }
 
  ModInt operator-(const ModInt &p) const { return ModInt(*this) -= p; }
 
  ModInt operator*(const ModInt &p) const { return ModInt(*this) *= p; }
 
  ModInt operator/(const ModInt &p) const { return ModInt(*this) /= p; }
 
  bool operator==(const ModInt &p) const { return x == p.x; }
 
  bool operator!=(const ModInt &p) const { return x != p.x; }
 
  ModInt inverse() const {
    int a = x, b = mod, u = 1, v = 0, t;
    while(b > 0) {
      t = a / b;
      swap(a -= t * b, b);
      swap(u -= t * v, v);
    }
    return ModInt(u);
  }
 
  ModInt pow(int64_t n) const {
    ModInt ret(1), mul(x);
    while(n > 0) {
      if(n & 1) ret *= mul;
      mul *= mul;
      n >>= 1;
    }
    return ret;
  }
 
  friend ostream &operator<<(ostream &os, const ModInt &p) {
    return os << p.x;
  }
 
  friend istream &operator>>(istream &is, ModInt &a) {
    int64_t t;
    is >> t;
    a = ModInt< mod >(t);
    return (is);
  }
 
  static int get_mod() { return mod; }
};
 
using modint = ModInt< 1000000007 >;
template< typename T >
struct Combination {
  vector< T > _fact, _rfact, _inv;
 
  Combination(int sz) : _fact(sz + 1), _rfact(sz + 1), _inv(sz + 1) {
    _fact[0] = _rfact[sz] = _inv[0] = 1;
    for(int i = 1; i <= sz; i++) _fact[i] = _fact[i - 1] * i;
    _rfact[sz] /= _fact[sz];
    for(int i = sz - 1; i >= 0; i--) _rfact[i] = _rfact[i + 1] * (i + 1);
    for(int i = 1; i <= sz; i++) _inv[i] = _rfact[i] * _fact[i - 1];
  }
 
  inline T fact(int k) const { return _fact[k]; }
 
  inline T rfact(int k) const { return _rfact[k]; }
 
  inline T inv(int k) const { return _inv[k]; }
 
  T P(int n, int r) const {
    if(r < 0 || n < r) return 0;
    return fact(n) * rfact(n - r);
  }
 
  T C(int p, int q) const {
    if(q < 0 || p < q) return 0;
    return fact(p) * rfact(q) * rfact(p - q);
  }
 
  T H(int n, int r) const {
    if(n < 0 || r < 0) return (0);
    return r == 0 ? 1 : C(n + r - 1, r);
  }
};
 
ll modpow(ll x, ll n, ll mod) {
  ll res = 1;
  x %= mod;
  if(x == 0) return 0;
  while(n) {
    if(n&1) res = (res * x) % mod;
    x = (x * x) % mod;
    n >>= 1;
  }
  return res;
} 
inline long long mod(long long a, long long m) {
    return (a % m + m) % m;
}
template<typename T> 
struct BIT{
  int N;
  std::vector<T> node;
  BIT(){}
  BIT(int n){
    N = n;
    node.resize(N+10);
  }
  void build(int n) {
    N = n;
    node.resize(N+10);
  }
  /* a: 1-indexed */
  void add(int a, T x){
    for(int i=a; i<(int)node.size(); i += i & -i) node[i] += x;
  }

  /* [1, a] */
  T sum(int a){
    T res = 0;
    for(int x=a; x>0; x -= x & -x) res += node[x];
    return res;
  }

  /* [l, r] */
  T rangesum(int l, int r){
    return sum(r) - sum(l-1);
  }

  /* 
    a1+a2+...+aw >= valとなるような最小のwを返す
    @verify https://codeforces.com/contest/992/problem/E
  */
  int lower_bound(T val) {
    if(val < 0) return 0;

    int res = 0;
    int n = 1; 
    while (n < N) n *= 2;

    T tv=0;
    for (int k = n; k > 0; k /= 2) {
      if(res + k < N && node[res + k] < val){
        val -= node[res+k];
        res += k;
      }
    }
    return res+1; 
  }
};
struct UnionFind{
  std::vector<int> par;
  std::vector<int> siz;

  UnionFind(int sz_): par(sz_), siz(sz_) {
    for(int i=0; i<sz_; ++i) par[i] = i, siz[i] = 1;
  }

  void init(int sz_){
    par.resize(sz_);
    siz.resize(sz_);
    for(int i=0; i<sz_; ++i) par[i] = i, siz[i] = 1;
  }

  int root(int x){
    if(x == par[x]) return x;
    return par[x] = root(par[x]);
  }

  bool merge(int x, int y){
    x = root(x), y = root(y);
    if(x == y) return false;
    if(siz[x] < siz[y]) std::swap(x, y);
    siz[x] += siz[y];
    par[y] = x;
    return true;
  }

  bool issame(int x, int y){
    return root(x) == root(y);
  }

  int size(int x){
    return siz[root(x)];
  }
};
struct RollingHash{

    using ull = unsigned long long;
    const ull mod = (1ULL << 61) - 1;
    const ull MASK30 = (1ULL << 30) - 1;
    const ull MASK31 = (1ULL << 31) - 1;

    const ull MASK61 = mod;

    ull base;
    int n;
    vector<ull> hash, pow;

    RollingHash(const string &s)
    {
        random_device rnd;
        mt19937_64 mt(rnd());
        base = 1001;
        
        n = (int)s.size();
        hash.assign(n+1, 0);
        pow.assign(n+1, 1);
        
        for(int i=0; i<n; i++){
            hash[i+1] = calc_mod(mul(hash[i], base) + s[i]);
            pow[i+1] = calc_mod(mul(pow[i], base));
        }
    }

    ull calc_mod(ull x){
        ull xu = x >> 61;
        ull xd = x & MASK61;
        ull res = xu + xd;
        if(res >= mod) res -= mod;
        return res;
    }

    ull mul(ull a, ull b){
        ull au = a >> 31;
        ull ad = a & MASK31;
        ull bu = b >> 31;
        ull bd = b & MASK31;
        ull mid = ad * bu + au * bd;
        ull midu = mid >> 30;
        ull midd = mid & MASK30;
        return calc_mod(au * bu * 2 + midu + (midd << 31) + ad * bd);
    }

    //[l,r)のハッシュ値
    inline ull get(int l, int r){
        ull res = calc_mod(hash[r] + mod*3-mul(hash[l], pow[r-l]));
        return res;
    }
    //string tのハッシュ値
    inline ull get(string t){
        ull res = 0;
        for(int i=0; i<t.size(); i++){
            res = calc_mod(mul(res, base)+t[i]);
        }
        return res;
    }
    //string s中のtの数をカウント
    inline int count(string t) {
        if(t.size() > n) return 0;
        auto hs = get(t);
        int res = 0;
        for(int i=0; i<n-t.size()+1; i++){
            if(get(i, i+t.size()) == hs) res++; 
        }
        return res;
    }

    /* 
        concat 
        @verify https://codeforces.com/problemset/problem/514/C
    */
    inline ull concat(ull h1, ull h2, int h2len){
      return calc_mod(h2 + mul(h1, pow[h2len]));
    }

    // LCPを求める S[a:] T[b:]
    inline int LCP(int a, int b){
        int len = min((int)hash.size()-a, (int)hash.size()-b);
        
        int lb = -1, ub = len;
        while(ub-lb>1){
            int mid = (lb+ub)/2;

            if(get(a, a+mid) == get(b, b+mid)) lb = mid;
            else ub = mid;
        }
        return lb;
    }
};

int main() {  
  cin.tie(0);
  ios::sync_with_stdio(false);
  cout << fixed << setprecision(12);
  
  int h, w; cin >> h >> w;
  h += 2; w += 2;
  vector<vector<char>> f(h, vector<char>(w, '.'));
  for(int i=1; i<h-1; i++) {
    for(int j=1; j<w-1; j++) {
      cin >> f[i][j];
    }
  }
  
  vector<pair<double, int>> v;
  REP(i,h-1) {
    REP(j,w-1) {
      int num = 0;
      double arg = atan2(h-2-i, j);
      if(f[i][j] == '#' && f[i][j+1] == '.' && f[i+1][j] == '.' && f[i+1][j+1] == '.') {
        v.push_back({arg, 1});
      }
      if(f[i][j] == '.' && f[i][j+1] == '#' && f[i+1][j] == '#' && f[i+1][j+1] == '#') {
        v.push_back({arg, 1});
      }
      if(f[i][j] == '#' && f[i][j+1] == '#' && f[i+1][j] == '#' && f[i+1][j+1] == '.') {
        v.push_back({arg, -1});
      }
      if(f[i][j] == '.' && f[i][j+1] == '.' && f[i+1][j] == '.' && f[i+1][j+1] == '#') {
        v.push_back({arg, -1});
      }
    }
  } 
  sort(all(v));
  int ans = 2;
  int cnt = 1;
  REP(i,v.size()) {
    cnt += v[i].second;
    ans = max(ans, cnt);
  }
  cout << ans << endl;
  return 0;
}
accuracy: 1
time_ms: 10
memory_kb: 6024
final_rank: 5