#include #include #include #include #include #include #include #include #include #include // #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" // #include "Src/DataStructure/SegmentTree/SegmentTree.hpp" // #include "Src/DataStructure/DisjointSetUnion/DisjointSetUnion.hpp" // #include "Src/DataStructure/Heap/BinaryHeap.hpp" namespace zawa {} using namespace zawa; // #include "atcoder/modint" // using mint = atcoder::modint998244353; // #include // #include // #include // #include // #include // #include // #include // #include // #include // #include // #include // #include // #include // #pragma GCC target("avx2") // #pragma GCC optimize("O3") // #pragma GCC optimize("unroll-loops") using namespace std; template ostream& operator<<(ostream& os, const pair& p) { os << '(' << p.first << ',' << p.second << ')'; return os; } template ostream& operator<<(ostream& os, const vector& v) { for (int i = 0 ; i < ssize(v) ; i++) os << v[i] << (i + 1 == ssize(v) ? "" : " "); return os; } /* * 1列目と2列目、H-1行目とH行目の間に操作をするとH+W回で移動できる * あきらかにH+W-2回が下界なので、H+W-2かH+W-1かを判定できれば良い * H+W-2は右下移動だけで到達可能かを判定すれば良くて、簡単。 * H+W-1は? * - 迂回する経路はありえなくて、一回操作をすると右下移動だけでできる * - (H,W)から左上移動で到達できるマスも計算すると判定ができる */ int main() { cin.tie(0); cout.tie(0); ios::sync_with_stdio(0); cout << fixed << setprecision(20); #if !defined DEBUG int H,W; cin >> H >> W; vector C(H,string(W,'.')); for (int i = 0 ; i < H ; i++) cin >> C[i]; const auto dp = [&]() { vector res(H,vector(W)); res[0][0] = 1; for (int i = 0 ; i < H ; i++) for (int j = 0 ; j < W ; j++) if (res[i][j]) { if (i + 1 < H and C[i+1][j] != '#') res[i+1][j] = 1; if (j + 1 < W and C[i][j+1] != '#') res[i][j+1] = 1; } return res; }(); const auto ep = [&]() { vector res(H,vector(W)); res[H-1][W-1] = 1; for (int i = H - 1 ; i >= 0 ; i--) for (int j = W - 1 ; j >= 0 ; j--) if (res[i][j]) { if (i >= 1 and C[i-1][j] != '#') res[i-1][j] = 1; if (j >= 1 and C[i][j-1] != '#') res[i][j-1] = 1; } return res; }(); if (dp[H-1][W-1]) { cout << H + W - 2 << '\n'; return 0; } vector row1(H,W),row2(H,-1); vector col1(W,H),col2(W,-1); for (int i = 0 ; i < H ; i++) for (int j = 0 ; j < W ; j++) { if (dp[i][j]) { row1[i] = min(row1[i],j); col1[j] = min(col1[j],i); } if (ep[i][j]) { row2[i] = max(row2[i],j); col2[j] = max(col2[j],i); } } bool can = 0; for (int i = 0 ; i + 1 < H ; i++) can |= row1[i] <= row2[i+1]; for (int i = 0 ; i + 1 < W ; i++) can |= col1[i] <= col2[i+1]; cout << (can ? H + W - 1 : H + W) << '\n'; #else mt19937_64 mt{random_device{}()}; for (int testcase = 0 ; ; ) { cerr << "----------" << ++testcase << "----------" << endl; auto a = solve(), b = naive(); if (a != b) { // print testcase cerr << "you: " << a << endl; cout << "correct: " << b << endl; exit(0); } } #endif }