結果

問題 No.2657 Falling Block Game
ユーザー as277575as277575
提出日時 2024-03-02 01:59:30
言語 C++17
(gcc 12.3.0 + boost 1.83.0)
結果
WA  
実行時間 -
コード長 35,241 bytes
コンパイル時間 3,569 ms
コンパイル使用メモリ 213,856 KB
実行使用メモリ 17,552 KB
最終ジャッジ日時 2024-09-29 15:45:42
合計ジャッジ時間 9,002 ms
ジャッジサーバーID
(参考情報)
judge3 / judge2
このコードへのチャレンジ
(要ログイン)

テストケース

テストケース表示
入力 結果 実行時間
実行使用メモリ
testcase_00 WA -
testcase_01 WA -
testcase_02 WA -
testcase_03 AC 2 ms
6,816 KB
testcase_04 AC 55 ms
17,264 KB
testcase_05 WA -
testcase_06 WA -
testcase_07 WA -
testcase_08 WA -
testcase_09 WA -
testcase_10 WA -
testcase_11 WA -
testcase_12 WA -
testcase_13 WA -
testcase_14 WA -
testcase_15 WA -
testcase_16 WA -
testcase_17 WA -
testcase_18 WA -
testcase_19 WA -
testcase_20 WA -
testcase_21 WA -
testcase_22 WA -
testcase_23 WA -
testcase_24 WA -
testcase_25 WA -
testcase_26 WA -
testcase_27 WA -
testcase_28 WA -
testcase_29 WA -
testcase_30 WA -
testcase_31 WA -
testcase_32 WA -
testcase_33 WA -
testcase_34 WA -
testcase_35 WA -
testcase_36 WA -
testcase_37 WA -
testcase_38 WA -
testcase_39 WA -
権限があれば一括ダウンロードができます

ソースコード

diff #

#include <algorithm>
#include <bit>
#include <bitset>
#include <cassert>
#include <complex>
#include <climits>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <deque>
#include <iostream>
#include <map>
#include <iomanip>
#include <optional>
#include <random>
#include <ranges>
#include <unordered_set>
#include <unordered_map>
#include <vector>
#include <set>
#include <string>
#include <type_traits>
#include <variant>

using std::__gcd;
using std::bitset;
using std::cin;
using std::cerr;
using std::complex;
using std::cout;
using std::deque;
using std::endl;
using std::greater;
using std::hash;
using std::istream;
using std::min;
using std::map;
using std::max;
using std::multiset;
using std::nullopt;
using std::optional;
using std::ostream;
using std::pair;
using std::rotate;
using std::set;
using std::setprecision;
using std::string;
using std::string_view;
using std::swap;
using std::tie;
using std::to_string;
using std::tuple;
using std::unordered_map;
using std::unordered_set;
using std::vector;

#if __cplusplus >= 201709L
  using std::ranges::sort;
  using std::ranges::views::iota;
  using std::views::reverse;
  using std::views::filter;
  using std::views::transform;
#endif

#define L(expr) ([&](const auto& _) { return (expr) ; })
#define Map(expr) (transform((L((expr)))))
#define Filter(expr) (filter((L((expr)))))

template <typename T>
ostream& operator<< (ostream& o, const multiset<T>& v) {
 for (const auto& x : v) o << x << " ";
 return o;
}

template <typename T>
ostream& operator<< (ostream& o, const unordered_set<T>& v) {
 o << "{";
 for (const auto& x : v) o << x << " ";
 o << "}";
 return o;
}

template<typename T, typename U>
ostream& operator<< (ostream& o, const pair<T, U>& p) {
  o << "<" << p.first << ", " << p.second << ">";
  return o;
}

template <typename T>
ostream& operator<< (ostream& o, const vector<T>& v) {
 for (const auto& x : v) o << x << " ";
 return o;
}

template <typename T>
ostream& operator<< (ostream& o, const set<T>& v) {
 for (const auto& x : v) o << x << " ";
 return o;
}

template <typename T>
ostream& operator<< (ostream& o, const deque<T>& v) {
 for (const auto& x : v) o << x << " ";
 return o;
}

template <typename K, typename V>
ostream& operator<<(ostream& o, const unordered_map<K, V>& m) {
  o << "{";
  for (const auto& [k, v] : m)
    o << " " << k << ": " << v << ",";
  o << "}";
  return o;
}

template <typename K, typename V>
ostream& operator<<(ostream& o, const map<K, V>& m) {
  o << "{";
  for (const auto& [k, v] : m)
    o << " " << k << ": " << v << ",";
  o << "}";
  return o;
}

template <typename T>
ostream& operator<< (ostream& o, const vector<vector<T>>& v) {
 for (const auto& x : v) o << x << endl;
 return o;
}

ostream& operator<< (ostream& o, const vector<string>& v) {
 for (const auto& x : v) o << x << endl;
 return o;
}

void print_to(ostream& o) {
  o << endl;
};

template <typename T, typename... A>
void print_to(ostream& o, const T& t, const A&... a) {
  o << t << " ";
  print_to(o, a...);
}

template <typename... A>
void out(const A&... a) {
  print_to(cout, a...); 
}

template <typename T, typename... A>
const T& cerr_and_return(const T& t, const A&... a) {
  print_to(cerr, "\t", t, "  ←   ", a...);
  return t;
}

template <typename T, typename... A>
T& cerr_and_return(T& t, const A&... a) {
  print_to(cerr, "\t", t, "  ←   ", a...);
  return t;
}

#ifdef DEBUG
  #define err(...) print_to(cerr, "\t[", #__VA_ARGS__, "]", " = ", __VA_ARGS__)
#else
  #define err(...)
#endif

#ifdef DEBUG
  #define E(expr) (cerr_and_return((expr), (#expr)))
#else
  #define E(expr) (expr)
#endif

class in {
 public:
  in() {}
  in(istream &i) : i(i) {}
  in(int n) : n(n) {}

  template <typename T>
  operator T () {
    T n;
    i >> n;
    return n;
  }
  
  template <typename T>
  operator deque<T> () {
    deque<T> v(n ? n.value() : static_cast<int>(*this));
    for (auto& x : v) x = *this;
    return v;
  }
  
  template <typename T>
  operator multiset<T> () {
    return insert<multiset<T>>(n ? n.value() : static_cast<int>(*this));
  }
  
  template <typename T, typename U>
  operator pair<T, U> () {
    return {*this, *this};
  }
  
  template <typename T>
  operator complex<T> () {
    return {*this, *this};
  }

  template <typename T>
  operator set<T> () {
    return insert<set<T>>(n ? n.value() : static_cast<int>(*this));
  }
  
  template <typename T>
  operator vector<T> () {
    vector<T> v(n ? n.value() : static_cast<int>(*this));
    for (auto& x : v) x = static_cast<T>(*this);
    return v;
  }
  
 private:
  template <typename S>
  S insert(int n) {
    S s;
    while (n--) s.insert(static_cast<typename S::key_type>(*this));
    return s;
  }
  
  optional<int> n;
  istream& i = cin;
} _;

/*
template <typename T>
istream& operator>> (istream& i, T& t) {
  t = static_cast<T>(in(i));
  return i;
}
*/

// Test for complex integers modulo: pair<Mod<>, Mod<>>
// https://yukicoder.me/problems/no/2651

template <typename T>
using Complex = pair<T, T>;

template <typename U, typename V>
pair<U, V> operator += (pair<U, V>& p, const pair<U, V>& q) {
  p.first += q.first;
  p.second += q.second;
  return p;
}

template <typename U, typename V>
pair<U, V> operator + (pair<U, V> p, const pair<U, V>& q) {
  return p += q;
}

template <typename U, typename V>
pair<U, V> operator -= (pair<U, V>& p, const pair<U, V>& q) {
  p.first -= q.first;
  p.second -= q.second;
  return p;
}

template <typename U, typename V>
pair<U, V> operator - (pair<U, V> p, const pair<U, V>& q) {
  return p -= q;
}

template <typename U, typename V>
pair<U, V> operator * (pair<U, V> p, const pair<U, V>& q) {
  return p *= q;
}

template <typename U, typename V, typename W>
pair<U, V> operator * (pair<U, V> p, const W& q) {
  return p *= q;
}

template <typename U, typename V, typename W>
pair<U, V> operator * (const W& q, pair<U, V> p) {
  return {q * p.first, q * p.second};
}

template <typename U, typename V>
pair<U, V> operator *= (pair<U, V>& p, const pair<U, V>& q) {
  U new_first = p.first * q.first - p.second * q.second;
  V new_second = p.first * q.second + p.second * q.first;
  p.first = new_first;
  p.second = new_second;
  return p;
}

template <typename U, typename V, typename W>
pair<U, V> operator *= (pair<U, V>& p, const W& q) {
  p.first *= q;
  p.second *= q;
  return p;
}

template <typename U, typename V>
pair<U, V> operator / (pair<U, V> p, const pair<U, V>& q) {
  err("pair", p, "/", "pair", q);
  return p /= q;
}

template <typename U, typename V, typename W>
pair<U, V> operator / (pair<U, V> p, const W& q) {
  err("pair", p, "/", "scalar", q);
  return p /= q;
}

template <typename U, typename V, typename W>
pair<U, V> operator / (const W& q, pair<U, V> p) {
  return pair<U, V>{q, 0} / p;
}

template <typename S, typename T>
complex<T> operator / (const S& s, complex<T> c) {
  return complex<T>{s, 0} / c;
}

template <typename U, typename V, typename W, typename X>
pair<U, V> operator /= (pair<U, V>& p, const pair<W, X>& q) {
  err("pair", p, "/=", "pair", q);
  pair<W, X> c = {q.first, -q.second};
  p *= c;
  auto m2 = q * c;
  assert(m2.second == 0);
  p /= m2.first;
  return p;
}

template <typename U, typename V, typename W>
pair<U, V> operator /= (pair<U, V>& p, const W& q) {
  err("pair", p, "/=", "scalar", q);
  p.first /= q;
  p.second /= q;
  return p;
}

template <typename U, typename V>
double hypot(const pair<U, V>& p) {
  return hypot(1.0 * p.first, 1.0 * p.second);
}

template <typename U, typename V>
pair<U, V> conj(const pair<U, V>& p) {
  return {p.first, -p.second};
}


template <typename U, typename V>
struct std::hash<pair<U, V>> {
  std::size_t operator () (const pair<U, V>& p) const {
    return hash<U>{}(p.first) ^ (hash<V>{}(p.second) << 1); // https://en.cppreference.com/w/cpp/utility/hash 
  }
};

template <typename Element, typename... List>
struct Contains {
  static constexpr bool value = false;
};

template <typename Element, typename... List>
struct Contains<Element, Element, List...> {
  static constexpr bool value = true;
};

template <typename Element, typename Other, typename... List>
struct Contains<Element, Other, List...> {
  static constexpr bool value = Contains<Element, List...>::value;
};

template <typename... Args>
inline constexpr bool contains_v = Contains<Args...>::value;

struct Empty {};

#define TREE_SUM
#define TREE_MULTIPLY

template <typename V = long long>
struct FastTree {
  using K = long long;
  const K a = -1e18, b = 1e18;
  
  struct Node {
    Node *left = nullptr, *right = nullptr;
    V value = 0;
    #ifdef TREE_SUM
      V sum_ = 0;
    #endif
    
    #ifdef TREE_MULTIPLY
      V multiplier = 1;
    #endif
    
    deque<string> to_lines(K a, K b) const {
      const K m = a + (b - a + 1) / 2 - 1;
      
      deque<string> lines = left ? left->to_lines(a, m) : deque<string>{};
      
      if (right) {
        deque<string> right_lines = right->to_lines(m + 1, b);
        
        size_t pad = 0;
        for (string_view l : lines) pad = max(pad, l.size());
        for (string& l : lines) l += string(pad - l.size(), ' ') + ']';
      
        while (lines.size() < right_lines.size())
          lines.push_back(string(pad + !!pad, ' '));
        
        for (int i = 0; i < right_lines.size(); ++i)
         lines[i] += right_lines[i];
      }
      
      lines.push_front("[" + to_string(a) + " " + to_string(b));
      if (value != 0) lines[0] += (value >= 0 ? " +" : " ") + to_string(value);
      #ifdef TREE_MULTIPLY
        if (multiplier != 1) lines[0] += " *" + to_string(multiplier);
      #endif
      #ifdef TREE_SUM
        lines[0] += " s=" + to_string(sum_);
      #endif
          
      return lines; 
    }
  } root;
  
  V operator[] (const K k) const {
    if (k < a || b < k) return 0;
    K a = this->a, b = this->b, m;
    const Node* node = &root;
    V r = 0;
    while (node) {
      r += node->value;
      m = a + (b - a + 1) / 2 - 1; 
      if (k <= m) {
        b = m;
        node = node->left;
      } else {
        a = m + 1;
        node = node->right;
      }
    }
    return r;
  }

  #ifdef TREE_SUM
  V sum(const K l, const K r) const {
    static vector<tuple<K, K, const Node*
    #ifdef TREE_MULTIPLY
      , V
    #endif
    >> stack(128);
    int top = 0;
    stack[top] = {a, b, &root
    #ifdef TREE_MULTIPLY
      , 1
    #endif
    };
    K a, b, m;
    const Node* node;
    #ifdef TREE_MULTIPLY
      V multiplier;
    #endif
    V s = 0;
    while (top >= 0) {
      tie(a, b, node
      #ifdef TREE_MULTIPLY
        , multiplier
      #endif
      ) = stack[top--];
      if (l <= a && b <= r) s +=
        #ifdef TREE_MULTIPLY
          multiplier *
        #endif
        node->sum_;
      else {
        s += max(static_cast<K>(0), 1 + min(r, b) - max(l, a)) * node->value
        #ifdef TREE_MULTIPLY
          * multiplier
        #endif
        ;
        m = a + (b - a + 1) / 2 - 1;
        if (l <= m && a <= r && node->left) stack[++top] = {a, m, node->left
        #ifdef TREE_MULTIPLY
          , multiplier * node->multiplier
        #endif
        };
        if (l <= b && m <= r && node->right) stack[++top] = {m + 1, b, node->right
        #ifdef TREE_MULTIPLY
          , multiplier * node->multiplier
        #endif
        }; 
      }
    }
    return s;
  }
  #endif
  
  void add(const K l, const K r, V v) {
    static vector<tuple<K, K, Node*, char>> stack(128);
    int top = 0;
    stack[top] = {a, b, &root, 0};
    K a, b, m;
    Node* node;
    bool visited;
    while (top >= 0) {
      tie(a, b, node, visited) = stack[top];
      //err(a, b, node, top, l, r);
      if (visited) {
        --top;
        #ifdef TREE_MULTIPLY
          if (!(b < l || r < a) && !(l <= a && b <= r)) v *= node->multiplier;
        #endif
        //err("exiting", a, b, node->value);
        node->sum_ = node->value * (b - a + 1);
        if (node->left) node->sum_ += node->left->sum_
          #ifdef TREE_MULTIPLY
            * node->multiplier
          #endif
        ;
        if (node->right) node->sum_ += node->right->sum_
          #ifdef TREE_MULTIPLY
            * node->multiplier
          #endif
        ;
      } else {
        //err("entering", a, b);
        std::get<3>(stack[top]) = true;
        if (b < l || r < a);
        else if (l <= a && b <= r) { node->value += v; }
        else {
          #ifdef TREE_MULTIPLY
            v /= node->multiplier;
          #endif
          m = a + (b - a + 1) / 2 - 1;
          if (l <= m) {
            if (!node->left) node->left = new Node;
            stack[++top] = {a, m, node->left, false};
          }
          if (m < r) {
            if (!node->right) node->right = new Node;
            stack[++top] = {m + 1, b, node->right, false};
          }
        }
      }
    }
  }
  
  #ifdef TREE_MULTIPLY
  void multiply(const K l, const K r, const V v) {
    static vector<tuple<K, K, Node*, bool>> stack(128);
    int top = 0;
    stack[top] = {a, b, &root, false};
    K a, b, m;
    Node* node;
    bool visited;
    while (top >= 0) {
      tie(a, b, node, visited) = stack[top];
      //err(a, b, node, top, l, r);
      if (visited) {
        --top;
        //err("exiting", a, b, node->value);
        node->sum_ = node->value * (b - a + 1);
        if (node->left) node->sum_ += node->left->sum_
          #ifdef TREE_MULTIPLY
            * node->multiplier
          #endif
        ;
        if (node->right) node->sum_ += node->right->sum_
          #ifdef TREE_MULTIPLY
            * node->multiplier
          #endif
        ;
      } else {
        //err("entering", a, b);
        std::get<3>(stack[top]) = true;
        if (b < l || r < a);
        else if (l <= a && b <= r) {
          node->value *= v;
          node->multiplier *= v;
        }
        else {
          m = a + (b - a + 1) / 2 - 1;
          if (l <= m) {
            if (!node->left) node->left = new Node;
            stack[++top] = {a, m, node->left, false};
          }
          if (m < r) {
            if (!node->right) node->right = new Node;
            stack[++top] = {m + 1, b, node->right, false};
          }
        }
      }
    }
  }
  #endif
  
  friend ostream& operator << (ostream& o, const FastTree& t) {
    deque<string> lines = t.root.to_lines(t.a, t.b);
    size_t pad = 0;
    for (string_view l : lines) pad = max(pad, l.size());
    for (string& l : lines) l += string(pad - l.size(), ' ') + ']';
    for (string_view l : lines) o << l << endl;
    return o;
  }
};


struct Sum {};


template <typename V = long long>
struct Tree {
  const long long a, b;
  
  using Interval = pair<long long, long long>;
  
  inline static pair<Interval, Interval> split(const Interval& i) {
    auto [l, r] = i;
    long long m = l + (r - l + 1) / 2 - 1;
    return {{l, m}, {m + 1, r}};
  }
  
  inline static bool in(const Interval& i, const Interval& j) {
    return j.first <= i.first && i.second <= j.second;
  }
  
  inline static bool disjoint(const Interval& i, const Interval& j) {
    return i.second < j.first || j.second < i.first;
  }
  
  inline static bool intersect(const Interval& i, const Interval& j) {
    return !disjoint(i, j);
  }
  
  struct Node {
    #ifdef TREE_MULTIPLY
      V subtree_multiplier = 1;
    #endif
    V value = 0 /*,,  min_ = 0, max_ = 0 */;
    V sum_ = 0;
    Node *left = nullptr, *right = nullptr;
    
    ~Node() {
      if (left) delete left;
      if (right) delete right;
    }
    
    template <typename T>
    void set(const Interval& ni, long long l, const vector<T>& v) {
      Interval vi = {l, l + v.size() - 1};
      if (disjoint(ni, vi)) return;
      assert(value == 0);
      #ifdef TREE_MULTIPLY
        assert(subtree_multiplier == 1);
      #endif
      if (ni.first == ni.second) {
        value = v[ni.first - l];
      } else {
        auto [li, ri] = split(ni);
        if (intersect(li, vi)) {
          if (!left) left = new Node;
          left->set(li, l, v);
        }
        if (intersect(ri, vi)) {
          if (!right) right = new Node;
          right->set(ri, l, v);
        }
      }
      update(ni);
    }
    
    void set(const Interval& ni, const Interval& vi, V v) {
      if (disjoint(ni, vi)) return;
      if (in(ni, vi)) {
        value = v;
        #ifdef TREE_MULTIPLY
          subtree_multiplier = 1;
        #endif
        if (left) delete left; left = nullptr;
        if (right) delete right; right = nullptr;
      } else {
        v -= value;
        #ifdef TREE_MULTIPLY
          assert(subtree_multiplier != 0);
          v /= subtree_multiplier;
        #endif
        auto [li, ri] = split(ni);
        if (intersect(li, vi)) {
          if (!left) left = new Node;
          left->set(li, vi, v);
        }
        if (intersect(ri, vi)) {
          if (!right) right = new Node;
          right->set(ri, vi, v);
        }
      }
      update(ni);
    }
    
    
    void add(const Interval& ni, const Interval& vi, V v
      #ifdef TREE_MULTIPLY
        , V denominator
      #endif
    ) {
      if (disjoint(ni, vi)) return;
      if (in(ni, vi)) {
        value += v
          #ifdef TREE_MULTIPLY
            / denominator
          #endif
        ;
      } else {
        auto [li, ri] = split(ni);
        if (intersect(li, vi)) {
          if (!left) left = new Node;
          left->add(li, vi, v
            #ifdef TREE_MULTIPLY
              , denominator * subtree_multiplier
            #endif
          );
        }  
        if (intersect(ri, vi)) {
          if (!right) right = new Node;
          right->add(ri, vi, v
            #ifdef TREE_MULTIPLY
              , denominator * subtree_multiplier
            #endif
          );
        }
      }
      update(ni);
    }
    
    void multiply(const Interval& ni, const Interval& vi, V v) {
      if (disjoint(ni, vi)) return;
      if (v == 0) {
        set(ni, vi, 0);
      } else if (in(ni, vi)) {
        value *= v;
        subtree_multiplier *= v;
      } else {
        auto [li, ri] = split(ni);
        if (!left) left = new Node;
        if (!right) right = new Node;
        left->add(li, li, value, subtree_multiplier);
        right->add(ri, ri, value, subtree_multiplier);
        value = 0;
        left->multiply(li, vi, v);
        right->multiply(ri, vi, v);
      }
      update(ni);
    }
    
    void get(const Interval& ni, const Interval& qi, vector<V>& result,
        #ifdef TREE_MULTIPLY
          V multiplier = 1, 
        #endif
        V addition = 0) {
      if (disjoint(ni, qi)) return;
      V v  = 
      #ifdef TREE_MULTIPLY
        multiplier *
      #endif
        value + addition;
      if (ni.first == ni.second) {
        result.push_back(v);
      } else {
        const auto [li, ri] = split(ni);
        
        if (left) {
          left->get(li, qi, result, 
            #ifdef TREE_MULTIPLY
              multiplier * subtree_multiplier,
            #endif
            v);
        } else {
          for (long long i = std::max(li.first, qi.first);
              i <= std::min(li.second, qi.second); ++i)
            result.push_back(v);
        }
        
        if (right) {
          right->get(ri, qi, result,
            #ifdef TREE_MULTIPLY
              multiplier * subtree_multiplier,
            #endif
            v);
        } else {
          for (long long i = std::max(ri.first, qi.first);
               i <= std::min(ri.second, qi.second); ++i)
            result.push_back(v);
        }
      }
    }
    
    V sum(const Interval& ni, const Interval& qi, bool cache=true) {
      if (disjoint(ni, qi)) return 0;
      if (in(ni, qi) && cache) return sum_;
      auto [li, ri] = split(ni);
      return value * (std::min(ni.second, qi.second) - std::max(ni.first, qi.first) + 1)
        + 
        #ifdef TREE_MULTIPLY
          subtree_multiplier *
        #endif
        (
          (left ? left->sum(li, qi) : 0) +
          (right ? right->sum(ri, qi) : 0)); 
    }
    /*
    V min(const Interval& ni, const Interval& qi, bool cache=true) {
      assert(intersect(ni, qi));
      if (in(ni, qi) && cache) return min_;
    
      auto [li, ri] = split(ni);
      V kids = 0;
      if (intersect(li, qi) && intersect(ri, qi))
        kids = std::min(left ? left->min(li, qi) : 0, right ? right->min(ri, qi) : 0);
      else if (intersect(li, qi) && left)
        kids = left->min(li, qi);
      else if (intersect(ri, qi) && right)
        kids = right->min(ri, qi);
      return value + /*subtree_multiplier **/ /*kids;
    }*/
    
    // UNTESTED
    /*
    V max(const Interval& ni, const Interval& qi, bool cache=true) {
      assert(intersect(ni, qi));
      if (in(ni, qi) && cache) return max_;
    
      auto [li, ri] = split(ni);
      V kids = 0;
      if (intersect(li, qi) && intersect(ri, qi))
        kids = std::max(left ? left->max(li, qi) : 0, right ? right->max(ri, qi) : 0);
      else if (intersect(li, qi) && left)
        kids = left->max(li, qi);
      else if (intersect(ri, qi) && right)
        kids = right->max(ri, qi);
      return value + /*subtree_multiplier  *  kids;
    }*/
    
    void update(const Interval& i) {
      sum_ = sum(i, i, false);
      //max_ = max(i, i, false);
      //min_ = min(i, i, false);
    }
    /*
    void print() {
      if (left) left->print();
      if (value)
        //cout << "[" << a << ", " << b << "; len=" << b - a + 1 << "] " << value << " " << sum_ << endl; 
      if (right) right->print();
    }*/
  } root;
  
  Tree(long long a = -1e18, long long b = 1e18): a(a), b(b) {}
  
  void add(long long l, long long r, V v) {
    root.add({a, b}, {l, r}, v
      #ifdef TREE_MULTIPLY
        , 1
      #endif
    );
  }
  
  #ifdef TREE_MULTIPLY
  void multiply(long long l, long long r, V v) {
    root.multiply({a, b}, {l, r}, v);
  }
  #endif
  
  void set(long long l, long long r, V v) {
    root.set({a, b}, {l, r}, v);
  }
  
  template <typename T>
  void set(long long l, const vector<T>& v) {
    root.set({a, b}, l, v);
  }
  
  vector<V> get(long long l, long long r) {
    vector<V> result;
    result.reserve(r - l + 1);
    root.get({a, b}, {l, r}, result);
    return result;
  }
  
  V sum(long long l, long long r) {
    return root.sum({a, b}, {l, r});
  }
  
  
  /*
  V max(long long l, long long r) {
    return root.max({a, b}, {l, r});
  }
 
  V min(long long l, long long r) {
    return root.min({a, b}, {l, r});
  }*/
};

auto read_undirected(int n, int m) {
  vector e(n + 1, vector<int>());
  while (m--) {
    int u = _, v = _;
    e[u].push_back(v);
    e[v].push_back(u);
  }
  return e;
}

struct GraphSearchResult {
    GraphSearchResult(int size): d(size, -1), p(size), v_to_cc(size, -1) {};
  
    vector<int> postorder, d, p, v_to_cc;
    vector<vector<int>> cc;
};

GraphSearchResult dfs(const vector<vector<int>>& edges) {
  GraphSearchResult r(edges.size());
  auto& [postorder, d, p, v_to_cc, cc] = r;
  vector<pair<int, int>> q;
  for (int s = 1; s < edges.size(); ++s) if (d[s] < 0) {
    cc.push_back({});
    q.push_back({0, s});
    while (q.size()) {
      auto [w, u] = q.back();
      q.pop_back();
      if (d[u] >= 0) continue;
      postorder.push_back(u);
      d[u] = d[w] + 1;
      p[u] = w;
      v_to_cc[u] = cc.size() - 1;
      cc.back().push_back(u);
      for (int v : edges[u]) q.push_back({u, v});
    }
  } 
  std::reverse(postorder.begin(), postorder.end());
  return r;
}

vector<int> return_vertices(const vector<vector<int>>& edges, const GraphSearchResult& s) {
  vector<int> r(s.p.size(), -1);
  for (int u : s.postorder) {
    r[u] = u;
    int b = s.d[u];
    for (int v : edges[u]) if (v != s.p[u]) {
      int c = s.p[v] == u ? r[v] : v;
      if (s.d[c] < b) { b = s.d[c], r[u] = c; }
    }
  }
  return r;
}

struct GcdResult {
  long long g;
  long long x;
  long long y;
};

GcdResult extended_gcd(const long long aa, const long long bb) {
  assert(aa || bb);
  long long a = abs(aa), b = abs(bb);
  bool swapped = b > a;
  if (swapped) swap(a, b);
  static vector<long long> k(512);
  int i = 0;
  while (b) {
    k[i++] = a / b;
    a %= b;
    swap(a, b);
  }
  assert(i <= 512);
  long long x = 1, y = 0;
  while (i) {
    swap(x, y);
    y -= x * k[--i];
  }
  if (swapped) swap(x, y);
  return {a, aa < 0 ? -x : x, bb < 0 ? -y : y};
}

long long inv(long long a, long long m) {
  GcdResult r = extended_gcd(a, m);
  assert(r.g == 1);
  long long result = (r.x % m + m) % m;
  assert(0 <= result);
  assert(result < m);
  return result;
}

long long lcm(long long a, long long b) {
  return (a / std::gcd(a, b)) * b;
}

inline long long power(long long a, long long b, long long m) {
  long long r = 1;
  for (long long i = 0, e = (a % m); (1 << i) <= b; ++i, e = (e * e) % m)
    if (b & (1 << i)) r = (r * e) % m;
  return r;
}

struct Operators {
  /*
  inline friend auto operator -= (auto& f, const auto& g) {
    return f += -g;
  }
  
  inline friend auto operator /= (auto& f, const auto& g) {
    return f *= g.inv();
  }
  */
  
};

struct Fraction : Operators {

  inline friend Fraction operator -= (Fraction& f, const Fraction& g) {
    return f += -g;
  }
  
  inline friend Fraction operator /= (Fraction& f, const Fraction& g) {
    return f *= g.inv();
  }

  friend Fraction operator + (Fraction f, const Fraction& g) {
    return f += g;
  }
  
  friend Fraction operator - (Fraction f, const Fraction& g) {
    return f -= g;
  } 
  
  friend Fraction operator * (Fraction f, const Fraction& g) {
    return f *= g;
  }

  friend Fraction operator / (Fraction f, const Fraction& g) {
    return f /= g;
  }
  
  friend bool operator == (const Fraction& f, const Fraction& g) {
    long long l = lcm(f.denominator, g.denominator);
    return f.numerator * (l / f.denominator) == g.numerator * (l / g.denominator);
  }
  
  friend bool operator < (const Fraction& f, const Fraction& g) {
    long long l = lcm(f.denominator, g.denominator);
    return f.numerator * (l / f.denominator) < g.numerator * (l / g.denominator);
  }

  long long numerator = 0, denominator = 1;
  
  Fraction() {}
  Fraction(long long n) : numerator(n) {}
  Fraction(long long n, long long d) : numerator(n), denominator(d) {
    simplify();
  }
  
  Fraction operator += (const Fraction& f) {
    long long l = lcm(denominator, f.denominator);
    numerator = numerator * (l / denominator) + f.numerator * (l / f.denominator);
    denominator = l;
    simplify();
    return *this;
  }
  
  Fraction operator - () const {
    return {-numerator, denominator};
  }
  
  Fraction operator *= (const Fraction& f) {
    long long g1 = __gcd(numerator, f.denominator),
      n1 = numerator / g1,
      d1 = f.denominator / g1,
      g2 = __gcd(denominator, f.numerator),
      n2 = f.numerator / g2,
      d2 = denominator / g2;
    numerator = n1 * n2;
    denominator = d1 * d2;
    simplify();
    return *this;
  }

  Fraction inv() const {
    return {denominator, numerator};
  }
  
  void simplify() {
    long long g = __gcd(numerator, denominator);
    numerator /= g;
    denominator /= g;
    if (denominator < 0) {
      numerator = -numerator;
      denominator = -denominator;
    }
  }
  
  friend ostream& operator << (ostream& o, const Fraction& f) {
    o << f.numerator << "/" << f.denominator ;
    return o;
  }
};

template <long long M=998244353>
struct Mod {
  
  inline Mod<M> operator -= (Mod<M> g) {
    return value = (value + M - g.value) % M;
  }
  
  inline Mod<M> operator /= (Mod<M> g) {
    return  value = (value * ::inv(g.value, M)) % M;
  }
  
  inline friend Mod<M> operator + (Mod<M> f, Mod<M> g) {
    return f += g;
  }
  
  inline friend Mod<M> operator - (Mod<M> f, Mod<M> g) {
    return f -= g;
  } 
  
  inline friend Mod<M> operator * (Mod<M> f, Mod<M> g) {
    return f *= g;
  }

  inline friend Mod<M> operator / (Mod<M> f, Mod<M> g) {
    return f /= g;
  }
  
  inline friend bool operator == (Mod<M> f, Mod<M> g) {
    return f.value == g.value;
  }
  
  inline friend bool operator < (Mod<M> f, Mod<M> g) {
    return f.value < g.value;
  }

  long long value;
  
  inline Mod(long long v = 0) : value((M + v % M) % M) {}
  
  inline Mod<M> operator += (Mod<M> b) {
    value = (value + b.value) % M;
    return *this;
  }
  
  inline Mod<M> operator - () const {
    return M - value;
  }
  
  inline Mod<M> operator *= (Mod<M> b) {
    value = (value * b.value) % M;
    return *this;
  }

  inline Mod<M> inv() const {
    return ::inv(value, M);
  }
  
  inline friend ostream& operator << (ostream& o, Mod<M> a) {
    o << a.value;
    return o;
  }
  
  inline friend istream& operator >> (istream& i, Mod<M>& a) {
    return i >> a.value;
  }
};

map<long long, long long> factorize(long long n) {
  map<long long, long long> r;
  for (long long i = 2; i * i <= n; ++i)
    for (; n % i == 0; n /= i)
      ++r[i];
  if (n > 1) ++r[n];
  return r;
}

template<typename T, typename U>
auto cdiv(T t, U u) {
  return (t + u - 1) / u;
}

inline vector<int> subsets(int s) {
  vector<int> change;
  for (int t = s, b = 1 << __builtin_ctz(t) ; t; t ^= b, b = 1 << __builtin_ctz(t))
      change.push_back(b - (s & (b - 1)));
  vector<int> r = {0};
  int over = 1 << __builtin_popcount(s);
  for (int t = 1, st = 0; t < over; ++t) 
    r.push_back(st += change[__builtin_ctz(t)]);
  return r;
}

const vector<pair<int, int>> four_directions {{1, 0}, {-1, 0}, {0, 1}, {0, -1}};

template <typename V>
bool is_index(const vector<V>& v, int i, int j) {
  return 0 <= i && i < v.size() && 0 <= j && j < v[i].size();
}

template <typename V>
bool is_index(const vector<V>& v, pair<int, int> ij) {
  return is_index(v, ij.first, ij.second);
}

auto indices(const vector<string>& v) {
  vector<pair<int, int>> r;
  for (int i = 0; i < v.size(); ++i)
    for (int j = 0; j < v[i].size(); ++j)
      r.push_back({i, j});
  return r;
}

auto four_neighbors(const vector<string>& b, pair<int, int> i) {
  vector<pair<int, int>> r;
  for (auto d : four_directions)
    if (is_index(b, i + d))
      r.push_back(i + d);
  return r;
}

vector<string> get_rotated_clockwise(const vector<string>& t) {
  vector<string> r(t[0].size(), string(t.size(), ' '));
  for (int i = 0; i < t.size(); ++i)
    for (int j = 0; j < t[0].size(); ++j)
      r[j][t.size() - i - 1] = t[i][j];
  return r;
}

template <typename T>
long long sum(const T& t) {
  return std::accumulate(begin(t), end(t), 0ll);
}

vector<long long> get_partial_sums(const vector<long long>& v) {
  vector<long long> p {0};
  partial_sum(v.cbegin(), v.cend(), back_inserter(p));
  return p;
}

void Yes(bool b) {
  out(b ? "Yes" : "No");
}

// Wczytać wektor i inne kolekcje stringów

void testTreeParity() {
  {
    const long long M = 2000000000;
    Tree t(-M, M);
    FastTree<long long> f{-M, M};
    for (long long i = 0; ; ++i) {
      if (i % 100000 == 0) out(i);
      {
        long long a = rand() % M, b = rand() % M, v = rand() % M;
        if (a > b) swap(a, b);
        err("add", a, b, v);
        t.add(a, b, v);
        f.add(a, b, v);
      }
      {
        //cerr << f;
        long long k = rand() % M;
        long long tr = t.get(k, k)[0], fr = f[k];
        err("get", k, tr, fr); 
        assert(tr == fr);
      }
      #ifdef TREE_SUM
      {
        long long a = rand() % M, b = rand() % M;
        if (a > b) swap(a, b);
        long long tr = t.sum(a, b), fr = f.sum(a, b);
        if (tr != fr) {
          cerr << f;
          out("sum", a, b, tr, fr);
        }
        assert(tr == fr);
      }
      #endif
      #ifdef TREE_MULTIPLY
      {
        long long a = rand() % M, b = rand() % M, v = rand() % M;
        if (a > b) swap(a, b);
        err("multiply", a, b, v);
        t.multiply(a, b, v);
        f.multiply(a, b, v);
      }
      #endif
    }
  }
}

void testTreeSpeed() {
  {
    const int M = 2000000000;
    //Tree<long long> t;
    FastTree<long long> t;
    for (long long i = 0; i < 500000; ++i) {
      if (i % 100000 == 0) err(i);
      {
        long long a = rand() % M, b = rand() % M, v = rand() % M;
        if (a > b) swap(a, b);
        //err("add", a, b, v);
        t.add(a, b, v);
      }
      {
        //cerr << f;
        //long long k = rand() % M;
        //long long tr = t.sum(k, k);//t.get(k, k)[0];
        //long long fr = t[k];
      }
      {
        long long a = rand() % M, b = rand() % M;
        if (a > b) swap(a, b);
        t.sum(a, b);
      }
    }
  }
}

vector<string> gen(int h, int w) {
  vector<string> g(h, string(w, '.'));
  for (int i = 1; i < h - 1; ++i)
    for (int j = 0; j < w; ++j)
      g[i][j] = rand() % 2 ? '.' : '#';
  return g;
}

vector<vector<int>> brut(const vector<string>& g) {
  const int inf = 1e9 + 7, h = g.size(), w = g[0].size();
  vector d(h, vector<int>(w, inf));
  d[0] = vector<int>(w, 0);
  for (int i = 1; i < h; ++i) {
    for (int j = 0; j < w; ++j) {
      for (int k = j; k >= 0 && g[h - 1 - i][k] == '.'; --k)
        d[i][j] = min(d[i][j], max(abs(k - j), d[i - 1][k]));
      for (int k = j; k < w && g[h - 1 - i][k] == '.'; ++k)
        d[i][j] = min(d[i][j], max(abs(k - j), d[i - 1][k]));
    }
  }
  return d;
}

vector<vector<int>> solve(const vector<string>& g) {
  const int inf = 1e9 + 7, h = g.size(), w = g[0].size();
  vector d(h, vector<int>(w, inf));
  d[0] = vector<int>(w, 0);
  for (int i = 1; i < h; ++i) {
    err(i);
    multiset<int> left, mid, right;
    
    int pi = 0;
    vector<tuple<int, int, int, bool>> p;
    for (int k = 0; k < w; ++k) {
      err(k);
      if (g[h - 1 - i][k] == '.') {
      
      if (k == 0 || g[h - 1 - i][k - 1] == '#') {
        p.clear();
    for (int j = k; j < w && g[h - 1 - i][j] == '.'; ++j) if (int c = d[i - 1][j]; c < inf) {
      left.insert(j);
      p.emplace_back(j - c, j, c, true);
      p.emplace_back(j + c + 1, j, c, false);
    }
    std::sort(p.begin(), p.end());
    err("sorted");  
      pi = 0;
      }
      
      for (; pi < p.size() && std::get<0>(p[pi]) <= k; ++pi) {
        auto [jc, j, c, f] = p[pi];
        err(jc, j, c, f);
        if (f) {
          left.erase(left.find(j));
          mid.insert(c);
        } else {
          mid.erase(mid.find(c));
          right.insert(j);
        }
      }
      err("moved");
      d[i][k] = inf;
      
      if (left.size())  d[i][k] = min( d[i][k], *left.begin() - k);
      if (mid.size())  d[i][k] = min( d[i][k], *mid.begin());
      if (right.size())  d[i][k] = min( d[i][k], k - *--right.end());
      
      } else {
      
        left.clear();
        mid.clear();
        right.clear();
      
      }
    }
  }
  return d;
}

int main() {
  std::ios::sync_with_stdio(false);
  cout << setprecision(50);
  cerr << setprecision(50);
  /*
  for (int h = 3; h < 10; ++h)
    for (int w = 1; w < 10; ++w) {
      out(h, w);
      for (int iter = 0; iter < 100000; ++iter) {
        auto g = gen(h, w);
        auto rs = solve(g), rb = brut(g);
        
        if (iter % 100000 == 0 || rs != rb) {
          out(g);
          out("rs");
          out(rs);
          out("rb");
          out(rb);
          Yes(rs == rb);
        }
        assert(rs == rb);
      }
  }
  return 0;
  */
  int h = _, w = _;
  vector<string> g = in(h);
  auto r = solve(g), rb = solve(g);
  
  out(rb.back());
 
  return 0;
}

0