#include <iostream>
#include <vector>
#include <optional>

constexpr int inf = 1 << 30;


// @ 遅延伝搬セグメント木 (データ構造)
// * 区間更新, 区間取得 が O(logN) で達成可能である
// ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
//    struct monoid_lazy_segment_tree{
//        using value_type = ;          // データの型
//        using lazy_type = ;           // 遅延評価作用素の型
//        inline static constexpr value_type identity_element = 0;  // データの単位元
//        // データ型の演算 (クエリの畳み込み和の演算) : 他ライブラリでは f などで書かれている
//        static value_type operation(const value_type& x, const value_type& y){
//            return ;
//        }
//        // 遅延評価を実際に行う演算 : (更新(評価)されるデータ型の値, 遅延作用素, その区間幅) → 新しく評価するデータの値
//        static lazy_type merge(const value_type& x, const lazy_type& y, const int N){
//            return ;
//        }
//        // 遅延作用素の伝搬 (古い作用素, 新しい作用素) → (作用素)
//        static lazy_type propagate(const lazy_type& x, const lazy_type& y){
//            return ;
//        }
//    };
// ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
template <class monoid_lazy_segment_tree> class LazySegmentTree{
private:
    using element_t   = typename monoid_lazy_segment_tree::value_type;
    using lazy_t      = typename monoid_lazy_segment_tree::lazy_type;
    using lazy_opt_t  = std::optional<lazy_t>;
    const int height;              //  セグメント木の高さ : 要素数 2^k の k
    const int length;              //  セグメント木の要素数 : 2^k (dataの数は 2 * 2^k)
    std::vector<element_t> data;   //  要素の部分
    std::vector<lazy_opt_t> lazy;  //  遅延評価部分

    // セグメント木に必要な高さを計算する補助関数
    static int make_height(const int n){
        int res = 0; for(int len = 1; len < n; ++res, len <<= 1);
        return res;
    }
    // 葉である頂点 x に向かって根からトップダウンに遅延評価部(lazy)を伝搬させていく関数
    inline void calculateData(int x){
        for(int len = 1; x >>= 1; len <<= 1){
            const int c1 = x << 1, c2 = c1 | 1;
            data[x] = monoid_lazy_segment_tree::operation(
                lazy[c1] ? monoid_lazy_segment_tree::merge(data[c1], *lazy[c1], len) : data[c1],
                lazy[c2] ? monoid_lazy_segment_tree::merge(data[c2], *lazy[c2], len) : data[c2]
            );
        }
    }
    // 葉である頂点 x から 根に向かってボトムアップに 要素本体 (data) の値を lazy を元に更新していく関数
    inline void propagate(int x){
        for(int shift = height, len = 1 << shift; shift ; --shift, len >>= 1){
            const int idx = x >> shift;
            if(lazy[idx]){
                const int idx1 = idx << 1;
                lazy[idx1] = lazy[idx1] ? lazy_opt_t(monoid_lazy_segment_tree::propagate(*lazy[idx1], *lazy[idx])) : lazy[idx];
                const int idx2 = (idx << 1) | 1;
                lazy[idx2] = lazy[idx2] ? lazy_opt_t(monoid_lazy_segment_tree::propagate(*lazy[idx2], *lazy[idx])) : lazy[idx];
                data[idx] = monoid_lazy_segment_tree::merge(data[idx], *lazy[idx], len);
                lazy[idx] = std::nullopt;
            }
        }
        if(lazy[x]){ data[x] = monoid_lazy_segment_tree::merge(data[x], *lazy[x], 1); lazy[x] = std::nullopt; }
    }

public:
    LazySegmentTree(const std::vector<bool>& A):height(make_height(A.size())), length(1 << height){
        lazy.assign(2 * length, std::nullopt);
        data.resize(2 * length); 
        const int n = A.size();
        for(int i = 0; i < n; ++i) data[i + length] = {A[i], inf, i};
        for(int i = n; i < length; ++i) data[i + length] = {true, inf, i};
        std::fill(data.begin() + length + A.size(), data.end(), monoid_lazy_segment_tree::identity_element);
        for(int idx = length - 1; idx ; --idx) data[idx] = monoid_lazy_segment_tree::operation(data[idx << 1], data[(idx << 1) | 1]);
    }

    // 半開区間 [l, r) (0-indexed) に作用素 val を作用させる関数
    inline void update_range(int l, int r, const lazy_t& val){
        if(l >= r) return ;
        propagate(l += length); propagate(r += length - 1);
        for(int li = l, ri = r + 1; li < ri; li >>= 1, ri >>= 1){
            if(li & 1){ lazy[li] = lazy[li] ? monoid_lazy_segment_tree::propagate(*lazy[li], val) : val; li++; }
            if(ri & 1){ --ri; lazy[ri] = lazy[ri] ? monoid_lazy_segment_tree::propagate(*lazy[ri], val) : val; }
        }
        calculateData(l); calculateData(r);
    }
    // 半開区間 [l, r) (0-indexed) 上の畳み込み和 al * al+1 * ... * ar-1 を求める関数
    inline element_t fold_range(int l, int r){
        if(l >= r) return monoid_lazy_segment_tree::identity_element;
        propagate(l += length); propagate((r += length) - 1);
        element_t vl = monoid_lazy_segment_tree::identity_element, vr = monoid_lazy_segment_tree::identity_element;
        int len = 1;
        while(l < r){
            if(l & 1){
                vl = monoid_lazy_segment_tree::operation( vl, lazy[l] ? monoid_lazy_segment_tree::merge(data[l], *lazy[l], len) : data[l] ); l++;
            }
            if(r & 1){
                --r; vr = monoid_lazy_segment_tree::operation(lazy[r] ? monoid_lazy_segment_tree::merge(data[r], *lazy[r], len) : data[r], vr);
            }
            l >>= 1; r >>= 1; len <<= 1;
        }
        return monoid_lazy_segment_tree::operation(vl, vr);
    }
};



struct monoid_lazy_segment_tree{
    using value_type = std::tuple<bool, int, int>;          // データの型
    using lazy_type = int;           // 遅延評価作用素の型
    inline static constexpr value_type identity_element = {true, inf, -1};  // データの単位元
    // データ型の演算 (クエリの畳み込み和の演算) : 他ライブラリでは f などで書かれている
    static value_type operation(const value_type& x, const value_type& y){
        /// if(std::get<0>(x)) return x;
        return (x < y) ? x : y;
    }
    // 遅延評価を実際に行う演算 : (更新(評価)されるデータ型の値, 遅延作用素, その区間幅) → 新しく評価するデータの値
    static value_type merge(const value_type& x, const lazy_type& y, const int N){
        if(y == -1) return identity_element;
        return (std::get<1>(x) < y) ? x : value_type(std::get<0>(x), y, std::get<2>(x));
    }
    // 遅延作用素の伝搬 (古い作用素, 新しい作用素) → (作用素)
    static lazy_type propagate(const lazy_type& x, const lazy_type& y){
        return (x < y) ? x : y;
    }
};


int main(void){
    std::cin.tie(nullptr); std::cin.sync_with_stdio(false);
    int n, m, k; std::cin >> n >> m >> k; const int N = n * m;
    int x0, y0, x1, y1; std::cin >> x0 >> y0 >> x1 >> y1; --x0, --x1, --y0, --y1;
    std::vector<std::vector<bool>> Map(n, std::vector<bool>(m));
    for(int i = 0; i < n; ++i){ std::string S; std::cin >> S; for(int j = 0; j < m; ++j) Map[i][j] = (S[j] == '@'); }
    std::vector<std::vector<int>>   L(n, std::vector<int>(m)),
                                    R(n, std::vector<int>(m)),
                                    U(n, std::vector<int>(m)),
                                    D(n, std::vector<int>(m));
    for(int i = 0, idx = 0; i < n; ++i, idx += m){
        int l = -1; for(int j = 0; j < m; ++j){ 
            if(Map[i][j]) l = j; if(j - k - 1 > l) l = j - k - 1;
            L[i][j] = idx + l + 1; 
        }
        int r = m;  for(int j = m - 1; j >= 0; --j) { 
            if(Map[i][j]) r = j;  if(j + k + 1 < r) r = j + k + 1;
            R[i][j] = idx + r;
        }
    }
    for(int j = 0, idx = 0; j < m; ++j, idx += n){
        int u = -1; for(int i = 0; i < n; ++i) { 
            if(Map[i][j]) u = i;  if(i - k - 1 > u) u = i - k - 1;
            U[i][j] = idx + u + 1; 
        }
        int d = n;  for(int i = n - 1; i >= 0; --i) { 
            if(Map[i][j]) d = i; if(i + k + 1 < d) d = i + k + 1;
            D[i][j] = idx + d; 
        }
    }
    std::vector<bool> A(N);
    for(int i = 0, s = 0; i < n; ++i) for(int j = 0; j < m; ++j, ++s) A[s] = Map[i][j];
    LazySegmentTree<monoid_lazy_segment_tree> X(A);
    for(int j = 0, s = 0; j < m; ++j) for(int i = 0; i < n; ++i, ++s) A[s] = Map[i][j];
    LazySegmentTree<monoid_lazy_segment_tree> Y(A);

    X.update_range(x0 * m + y0, x0 * m + y0 + 1, 0);
    Y.update_range(y0 * n + x0, y0 * n + x0 + 1, 0);
    int res = -1;
    while(true){
        const auto vx = X.fold_range(0, N);
        const auto vy = Y.fold_range(0, N);
        int x, y, d;
        if(vx < vy){ if(std::get<0>(vx)) break; d = std::get<1>(vx); x = std::get<2>(vx) / m, y = std::get<2>(vx) % m; }
        else { if(std::get<0>(vy)) break; d = std::get<1>(vy); y = std::get<2>(vy) / n, x = std::get<2>(vy) % n; }
        if(d == inf or x < 0 or y < 0) break;
        if(x == x1 and y == y1){ res = d; break; }
        X.update_range(L[x][y], R[x][y], d + 1); X.update_range(x * m + y, x * m + y + 1, -1);

        Y.update_range(U[x][y], D[x][y], d + 1); Y.update_range(y * n + x, y * n + x + 1, -1);
    }
    if(res == -1) std::cout << "-1\n"; else std::cout << res << '\n';
    return 0;
}


Measured memory_bytes: 104672