Problem p02644 (C++)

Buggy submission (status: Time Limit Exceeded):
#include <bits/stdc++.h>
// #include <boost/multiprecision/cpp_int.hpp>
using namespace std;

#define all(a) (a).begin(), (a).end()
#define rall(a) (a).rbegin(), (a).rend()
#define MIN(a) *std::min_element((a).begin(), (a).end())
#define MAX(a) *std::max_element((a).begin(), (a).end())
#define SUM(a) std::accumulate((a).begin(), (a).end(), 0LL)
#define REP(i, n) for (std::size_t(i) = 0; (i) < (n); (i)++)
#define RREP(i, n) for (std::size_t(i) = (n)-1; (i) >= 0; (i)--)
#define FOR(i, m, n) for (std::size_t(i) = (m); (i) < (n); i++)
#define FORR(i, m, n) for (std::size_t(i) = (n)-1; (i) >= (m); i--)
#define debug(x) std::cerr << #x << " = " << x << '\n'
// #define int long long

using ll = long long;
using ull = unsigned long long;
using ld = long double;
using vl = std::vector<long long>;
using vvl = std::vector<std::vector<long long>>;
// using bint = boost::multiprecision::cpp_int;
// using rat = boost::rational<bint>;

constexpr int inf = (1 << 30) - 1;
constexpr long long INF = 1LL << 60;

inline void ios_() {
  std::cin.tie(nullptr);
  std::ios::sync_with_stdio(false);
}
template <typename T> inline T Div(const T &a, const T &b) {
  return (a + b - 1) / b;
}
template <typename T> bool chmin(T &a, const T &b) {
  if (a > b) {
    a = b;
    return true;
  }
  return false;
}
template <typename T> bool chmax(T &a, const T &b) {
  if (a < b) {
    a = b;
    return true;
  }
  return false;
}

template <typename T> inline void finish(const T &msg) {
  std::cout << msg << std::endl;
  std::exit(0);
}

template <typename T>
long long binarySearch(long long ng, long long ok, const T &fn) {
  while (std::abs(ok - ng) > 1) {
    T mid = (ok + ng) / 2;
    if (fn(mid))
      ok = mid;
    else
      ng = mid;
  }
  return ok;
}

struct ModInt {
  long long value;
  static const long long mod; // mod must be a prime number

  ModInt(long long v = 0) : value(((v % mod) + mod) % mod) {}

  ModInt pow(long long n) const {
    long long x = value, res = 1;
    while (n > 0) {
      if (n & 1) {
        res = res * x % mod;
      }
      x = x * x % mod;
      n >>= 1;
    }
    return ModInt(res);
  }

  ModInt inverse() const { return pow(mod - 2); }

  ModInt operator-() const { return ModInt((mod - value) % mod); }

  ModInt &operator+=(const ModInt &a) {
    value += a.value;
    value %= mod;
    return *this;
  }

  ModInt &operator-=(const ModInt &a) {
    value += (-a).value;
    value %= mod;
    return *this;
  }

  ModInt &operator*=(const ModInt &a) {
    value *= a.value;
    value %= mod;
    return *this;
  }

  ModInt &operator/=(const ModInt &a) { return (*this) *= a.inverse(); }

  ModInt operator+(const ModInt &a) const { return ModInt(*this) += a; }

  ModInt operator-(const ModInt &a) const { return ModInt(*this) -= a; }

  ModInt operator*(const ModInt &a) const { return ModInt(*this) *= a; }

  ModInt operator/(const ModInt &a) const { return ModInt(*this) /= a; }

  bool operator==(const ModInt &a) const { return value == a.value; }

  bool operator!=(const ModInt &a) const { return value != a.value; }

  friend std::istream &operator>>(std::istream &is, ModInt &a) {
    long long v;
    is >> v;
    a = v;
    return is;
  }

  friend std::ostream &operator<<(std::ostream &os, const ModInt &a) {
    os << a.value;
    return os;
  }

  static ModInt factorial(int n) {
    static std::vector<ModInt> fact(1 << 18);
    if (fact.size() <= n) {
      fact.resize(n + 1);
    }
    if (n < 0) {
      return 0;
    }
    if (n == 0) {
      return 1;
    }
    if (fact[n] != 0) {
      return fact[n];
    }
    return fact[n] = factorial(n - 1) * n;
  }

  static ModInt combin(int n, int k) {
    if (n < 0 || k < 0 || n < k) {
      return 0;
    }
    return factorial(n) / (factorial(k) * factorial(n - k));
  }
};
const long long ModInt::mod = 1e9 + 7;
// const long long ModInt::mod = 998244353;
using mint = ModInt;

#include <algorithm>
#include <deque>
#include <queue>
#include <vector>
using ll = long long;

struct Graph {
  struct Edge {
    int from;
    int to;
    ll cost;
    int dx, dy;
    Edge(int a, ll b) : to(a), cost(b) {}
    Edge(int a, int b, ll c) : from(a), to(b), cost(c) {}
    Edge(int a, int b, ll c, int x, int y)
        : from(a), to(b), cost(c), dx(x), dy(y) {}
  };

  int N;                                // 頂点数
  std::vector<std::vector<Edge>> edges; // 隣接リスト
  std::vector<ll> dist;                 // ノードの深さ
  std::vector<int> deg;                 // 入次数

  Graph(int n) : N(n), edges(n), dist(n, INF), deg(n, 0) {}

  void connect(int a, int b, ll c) { // 辺を追加
    edges[a].emplace_back(Edge(a, b, c));
    deg[b]++;
  }

  bool visited(int v) { return dist[v] < INF; }

  void resetDist() {
    for (int i = 0; i < N; i++) {
      dist[i] = INF;
    }
  }

  void dfs(int p, int v, ll d) { // 深さ優先探索
    if (visited(v))
      return;

    dist[v] = d;

    for (const Edge &e : edges[v]) {
      if (e.to == p)
        continue;
      dfs(v, e.to, d + e.cost);
    }
  }

  void bfs(int v) { // 幅優先探索
    std::queue<Edge> que;
    for (const Edge &e : edges[v]) {
      que.push(e);
      dist[e.to] = e.cost;
    }

    dist[v] = 0;

    while (!que.empty()) {
      int u = que.front().to;
      ll d = que.front().cost;
      que.pop();

      for (const Edge &e : edges[u]) {
        if (!visited(e.to)) {
          que.push(Edge(e.from, e.to, d + e.cost));
          dist[e.to] = d + e.cost;
        }
      }
    }
  }

  ll diameter() { // 木の直径を求める
    static ll res = INF;
    if (res != INF)
      return res; // 計算済みの場合

    dfs(-1, 0, 0); // 頂点0からの最遠頂点vを求める
    int v = std::max_element(dist.begin(), dist.end()) - dist.begin();

    resetDist();

    dfs(-1, v, 0); // vからの最遠頂点を求める

    return res = *std::max_element(dist.begin(),
                                   dist.end()); // この2頂点間の距離が直径
  }

  void dijkstra(int start) { // ダイクストラ法
    dist[start] = 0;

    auto fn = [](const Edge &a, const Edge &b) { return a.cost > b.cost; };
    std::priority_queue<Edge, std::vector<Edge>, decltype(fn)> que(fn);

    for (const Edge &e : edges[start])
      que.push(e);

    while (!que.empty()) {
      auto v = que.top().to;
      auto d = que.top().cost;
      que.pop();

      if (visited(v))
        continue;
      else
        dist[v] = d;

      for (const Edge &e : edges[v]) {
        if (dist[e.to] == INF) {
          que.push(Edge(e.from, e.to, e.cost + d));
        }
      }
    }
  }
};

struct MatrixGraph : Graph {
  MatrixGraph(int n) : Graph(n) {
    for (int i = 0; i < n; i++) {
      for (int j = 0; j < n; j++) {
        edges[i].emplace_back(Edge(i, j, (i == j ? 0 : INF)));
      }
    }
  }

  void connect(int a, int b, ll c) { edges[a][b].cost = c; }

  void WarshallFloyd() {
    for (int k = 0; k < N; k++) {
      for (int i = 0; i < N; i++) {
        for (int j = 0; j < N; j++) {
          ll d = edges[i][k].cost + edges[k][j].cost;
          if (d < edges[i][j].cost) {
            edges[i][j].cost = d;
          }
        }
      }
    }
  }
};

struct GridGraph : Graph {
  int H, W;
  std::vector<std::vector<bool>> grid;
  std::vector<int> dx, dy;
  int K;

  GridGraph(int h, int w)
      : Graph(h * w), H(h), W(w), grid(h, std::vector<bool>(w, false)) {
    dx = {1, 0, -1, 0, 1, 1, -1, -1};
    dy = {0, 1, 0, -1, 1, -1, 1, -1};
  }

  void setGrid(int x, int y, bool b) { grid[x][y] = b; }

  bool out(int x, int y) { return (x < 0 || x >= H || y < 0 || y >= W); }

  int to1D(int x, int y) { return x * W + y; }

  int getx(int i) { return i / W; }

  int gety(int i) { return i % W; }

  void connectAll(bool diagonal) {
    for (int x = 0; x < H; x++) {
      for (int y = 0; y < W; y++) {
        if (!grid[x][y])
          continue;

        for (int k = 0; k < (diagonal ? 8 : 4); k++) {
          int nx = x + dx[k], ny = y + dy[k];
          if (out(nx, ny) || !grid[nx][ny])
            continue;
          connect(to1D(x, y), to1D(nx, ny), 1);
        }
      }
    }
  }

  void bfs(int v) { // 幅優先探索
    queue<Edge> que;
    que.push(Edge(-1, v, 0));
    dist[v] = 0;

    while (!que.empty()) {
      auto e = que.front();
      int u = e.to;
      ll d = e.cost;
      que.pop();

      REP(i, 4) {
        int x = getx(u), y = gety(u);
        int ddx = 0, ddy = 0;

        REP(j, K) {
          ddx += dx[i];
          ddy += dy[i];
          if (out(x + ddx, y + ddy) || !grid[x + ddx][y + ddy])
            break;
          int next = to1D(x + ddx, y + ddy);
          if (visited(next))
            continue;
          que.push(Edge(u, next, d + 1));
          chmin(dist[next], d + 1);
        }
      }
    }
  }
};

signed main() {
  int h, w, k;
  cin >> h >> w >> k;
  int x1, y1, x2, y2;
  cin >> x1 >> y1 >> x2 >> y2;
  x1--;
  y1--;
  x2--;
  y2--;

  GridGraph G(h, w);

  REP(i, h) {
    REP(j, w) {
      char c;
      cin >> c;
      G.setGrid(i, j, (c == '.'));
    }
  }

  G.K = k;

  G.bfs(G.to1D(x1, y1));

  ll ans = G.dist[G.to1D(x2, y2)];
  cout << (ans < INF ? ans : -1) << endl;

  return 0;
}


Fixed submission:
#include <bits/stdc++.h>
// #include <boost/multiprecision/cpp_int.hpp>
using namespace std;

#define all(a) (a).begin(), (a).end()
#define rall(a) (a).rbegin(), (a).rend()
#define MIN(a) *std::min_element((a).begin(), (a).end())
#define MAX(a) *std::max_element((a).begin(), (a).end())
#define SUM(a) std::accumulate((a).begin(), (a).end(), 0LL)
#define REP(i, n) for (std::size_t(i) = 0; (i) < (n); (i)++)
#define RREP(i, n) for (std::size_t(i) = (n)-1; (i) >= 0; (i)--)
#define FOR(i, m, n) for (std::size_t(i) = (m); (i) < (n); i++)
#define FORR(i, m, n) for (std::size_t(i) = (n)-1; (i) >= (m); i--)
#define debug(x) std::cerr << #x << " = " << x << '\n'
// #define int long long

using ll = long long;
using ull = unsigned long long;
using ld = long double;
using vl = std::vector<long long>;
using vvl = std::vector<std::vector<long long>>;
// using bint = boost::multiprecision::cpp_int;
// using rat = boost::rational<bint>;

constexpr int inf = (1 << 30) - 1;
constexpr long long INF = 1LL << 60;

inline void ios_() {
  std::cin.tie(nullptr);
  std::ios::sync_with_stdio(false);
}
template <typename T> inline T Div(const T &a, const T &b) {
  return (a + b - 1) / b;
}
template <typename T> bool chmin(T &a, const T &b) {
  if (a > b) {
    a = b;
    return true;
  }
  return false;
}
template <typename T> bool chmax(T &a, const T &b) {
  if (a < b) {
    a = b;
    return true;
  }
  return false;
}

template <typename T> inline void finish(const T &msg) {
  std::cout << msg << std::endl;
  std::exit(0);
}

template <typename T>
long long binarySearch(long long ng, long long ok, const T &fn) {
  while (std::abs(ok - ng) > 1) {
    T mid = (ok + ng) / 2;
    if (fn(mid))
      ok = mid;
    else
      ng = mid;
  }
  return ok;
}

struct ModInt {
  long long value;
  static const long long mod; // mod must be a prime number

  ModInt(long long v = 0) : value(((v % mod) + mod) % mod) {}

  ModInt pow(long long n) const {
    long long x = value, res = 1;
    while (n > 0) {
      if (n & 1) {
        res = res * x % mod;
      }
      x = x * x % mod;
      n >>= 1;
    }
    return ModInt(res);
  }

  ModInt inverse() const { return pow(mod - 2); }

  ModInt operator-() const { return ModInt((mod - value) % mod); }

  ModInt &operator+=(const ModInt &a) {
    value += a.value;
    value %= mod;
    return *this;
  }

  ModInt &operator-=(const ModInt &a) {
    value += (-a).value;
    value %= mod;
    return *this;
  }

  ModInt &operator*=(const ModInt &a) {
    value *= a.value;
    value %= mod;
    return *this;
  }

  ModInt &operator/=(const ModInt &a) { return (*this) *= a.inverse(); }

  ModInt operator+(const ModInt &a) const { return ModInt(*this) += a; }

  ModInt operator-(const ModInt &a) const { return ModInt(*this) -= a; }

  ModInt operator*(const ModInt &a) const { return ModInt(*this) *= a; }

  ModInt operator/(const ModInt &a) const { return ModInt(*this) /= a; }

  bool operator==(const ModInt &a) const { return value == a.value; }

  bool operator!=(const ModInt &a) const { return value != a.value; }

  friend std::istream &operator>>(std::istream &is, ModInt &a) {
    long long v;
    is >> v;
    a = v;
    return is;
  }

  friend std::ostream &operator<<(std::ostream &os, const ModInt &a) {
    os << a.value;
    return os;
  }

  static ModInt factorial(int n) {
    static std::vector<ModInt> fact(1 << 18);
    if (fact.size() <= n) {
      fact.resize(n + 1);
    }
    if (n < 0) {
      return 0;
    }
    if (n == 0) {
      return 1;
    }
    if (fact[n] != 0) {
      return fact[n];
    }
    return fact[n] = factorial(n - 1) * n;
  }

  static ModInt combin(int n, int k) {
    if (n < 0 || k < 0 || n < k) {
      return 0;
    }
    return factorial(n) / (factorial(k) * factorial(n - k));
  }
};
const long long ModInt::mod = 1e9 + 7;
// const long long ModInt::mod = 998244353;
using mint = ModInt;

#include <algorithm>
#include <deque>
#include <queue>
#include <vector>
using ll = long long;

struct Graph {
  struct Edge {
    int from;
    int to;
    ll cost;
    int dx, dy;
    Edge(int a, ll b) : to(a), cost(b) {}
    Edge(int a, int b, ll c) : from(a), to(b), cost(c) {}
    Edge(int a, int b, ll c, int x, int y)
        : from(a), to(b), cost(c), dx(x), dy(y) {}
  };

  int N;                                // 頂点数
  std::vector<std::vector<Edge>> edges; // 隣接リスト
  std::vector<ll> dist;                 // ノードの深さ
  std::vector<int> deg;                 // 入次数

  Graph(int n) : N(n), edges(n), dist(n, INF), deg(n, 0) {}

  void connect(int a, int b, ll c) { // 辺を追加
    edges[a].emplace_back(Edge(a, b, c));
    deg[b]++;
  }

  bool visited(int v) { return dist[v] < INF; }

  void resetDist() {
    for (int i = 0; i < N; i++) {
      dist[i] = INF;
    }
  }

  void dfs(int p, int v, ll d) { // 深さ優先探索
    if (visited(v))
      return;

    dist[v] = d;

    for (const Edge &e : edges[v]) {
      if (e.to == p)
        continue;
      dfs(v, e.to, d + e.cost);
    }
  }

  void bfs(int v) { // 幅優先探索
    std::queue<Edge> que;
    for (const Edge &e : edges[v]) {
      que.push(e);
      dist[e.to] = e.cost;
    }

    dist[v] = 0;

    while (!que.empty()) {
      int u = que.front().to;
      ll d = que.front().cost;
      que.pop();

      for (const Edge &e : edges[u]) {
        if (!visited(e.to)) {
          que.push(Edge(e.from, e.to, d + e.cost));
          dist[e.to] = d + e.cost;
        }
      }
    }
  }

  ll diameter() { // 木の直径を求める
    static ll res = INF;
    if (res != INF)
      return res; // 計算済みの場合

    dfs(-1, 0, 0); // 頂点0からの最遠頂点vを求める
    int v = std::max_element(dist.begin(), dist.end()) - dist.begin();

    resetDist();

    dfs(-1, v, 0); // vからの最遠頂点を求める

    return res = *std::max_element(dist.begin(),
                                   dist.end()); // この2頂点間の距離が直径
  }

  void dijkstra(int start) { // ダイクストラ法
    dist[start] = 0;

    auto fn = [](const Edge &a, const Edge &b) { return a.cost > b.cost; };
    std::priority_queue<Edge, std::vector<Edge>, decltype(fn)> que(fn);

    for (const Edge &e : edges[start])
      que.push(e);

    while (!que.empty()) {
      auto v = que.top().to;
      auto d = que.top().cost;
      que.pop();

      if (visited(v))
        continue;
      else
        dist[v] = d;

      for (const Edge &e : edges[v]) {
        if (dist[e.to] == INF) {
          que.push(Edge(e.from, e.to, e.cost + d));
        }
      }
    }
  }
};

struct MatrixGraph : Graph {
  MatrixGraph(int n) : Graph(n) {
    for (int i = 0; i < n; i++) {
      for (int j = 0; j < n; j++) {
        edges[i].emplace_back(Edge(i, j, (i == j ? 0 : INF)));
      }
    }
  }

  void connect(int a, int b, ll c) { edges[a][b].cost = c; }

  void WarshallFloyd() {
    for (int k = 0; k < N; k++) {
      for (int i = 0; i < N; i++) {
        for (int j = 0; j < N; j++) {
          ll d = edges[i][k].cost + edges[k][j].cost;
          if (d < edges[i][j].cost) {
            edges[i][j].cost = d;
          }
        }
      }
    }
  }
};

struct GridGraph : Graph {
  int H, W;
  std::vector<std::vector<bool>> grid;
  std::vector<int> dx, dy;
  int K;

  GridGraph(int h, int w)
      : Graph(h * w), H(h), W(w), grid(h, std::vector<bool>(w, false)) {
    dx = {1, 0, -1, 0, 1, 1, -1, -1};
    dy = {0, 1, 0, -1, 1, -1, 1, -1};
  }

  void setGrid(int x, int y, bool b) { grid[x][y] = b; }

  bool out(int x, int y) { return (x < 0 || x >= H || y < 0 || y >= W); }

  int to1D(int x, int y) { return x * W + y; }

  int getx(int i) { return i / W; }

  int gety(int i) { return i % W; }

  void connectAll(bool diagonal) {
    for (int x = 0; x < H; x++) {
      for (int y = 0; y < W; y++) {
        if (!grid[x][y])
          continue;

        for (int k = 0; k < (diagonal ? 8 : 4); k++) {
          int nx = x + dx[k], ny = y + dy[k];
          if (out(nx, ny) || !grid[nx][ny])
            continue;
          connect(to1D(x, y), to1D(nx, ny), 1);
        }
      }
    }
  }

  void bfs(int v) { // 幅優先探索
    queue<Edge> que;
    que.push(Edge(-1, v, 0));
    dist[v] = 0;

    while (!que.empty()) {
      auto e = que.front();
      int u = e.to;
      ll d = e.cost;
      que.pop();

      REP(i, 4) {
        int x = getx(u), y = gety(u);
        int ddx = 0, ddy = 0;

        REP(j, K) {
          ddx += dx[i];
          ddy += dy[i];
          if (out(x + ddx, y + ddy) || !grid[x + ddx][y + ddy])
            break;
          int next = to1D(x + ddx, y + ddy);
          if (dist[u] >= dist[next])
            break;
          if (visited(next))
            continue;
          que.push(Edge(u, next, d + 1));
          chmin(dist[next], d + 1);
        }
      }
    }
  }
};

signed main() {
  int h, w, k;
  cin >> h >> w >> k;
  int x1, y1, x2, y2;
  cin >> x1 >> y1 >> x2 >> y2;
  x1--;
  y1--;
  x2--;
  y2--;

  GridGraph G(h, w);

  REP(i, h) {
    REP(j, w) {
      char c;
      cin >> c;
      G.setGrid(i, j, (c == '.'));
    }
  }

  G.K = k;

  G.bfs(G.to1D(x1, y1));

  ll ans = G.dist[G.to1D(x2, y2)];
  cout << (ans < INF ? ans : -1) << endl;

  return 0;
}