// linux not windows
#include <cassert>

#include <algorithm>
#include <fstream>
#include <iostream>
using namespace std;

const int kMaxN = 2005, inf = 0x3f3f3f3f;

ifstream in;
//ofstream out;

const int BufferSize = 100000;
int BufferInd = BufferSize - 1;
char Buffer[BufferSize];

inline void verf() {
    if (++BufferInd == BufferSize) {
        BufferInd = 0; 
        cin.read(Buffer, BufferSize);
    }
}
#define CharB Buffer[BufferInd]
#define CharOk (('0' <= CharB and CharB <= '9')?(1):(0))

void cit(int &a) {
    verf();
    for (; not CharOk; verf())
        ;
    for (a = 0; CharOk; verf()) {
        a *= 10;
        a += CharB - '0';
    }
    return ;
}


pair<int, int> event[2 * kMaxN];
int eventz;

int Down[kMaxN][kMaxN], Up[kMaxN][kMaxN];
int Right[kMaxN][kMaxN], Left[kMaxN][kMaxN];

int n;
bool bad[kMaxN][kMaxN];
int el[kMaxN][kMaxN];
int aint[4 * kMaxN];

int C1[2 * kMaxN], L1[2 * kMaxN];

void aint_Update(int nod, int st, int dr, int c, int val) {
    if (st == dr) {
        aint[nod] = val;
    } else {
        int m = (st + dr) / 2;
        if (c <= m)
            aint_Update(2 * nod, st, m, c, val);
        else
            aint_Update(2 * nod + 1, m + 1, dr, c, val);
        aint[nod] = min(aint[2 * nod] + 1, aint[2 * nod]);
    }
}

int aint_query(int nod, int st, int dr, int c) {
    if (c <= st)
        return aint[nod];
    if (dr < c)
        return inf;
    
    int m = (st + dr) / 2;
    return min(
        aint_query(2 * nod, st, m, c),
        aint_query(2 * nod + 1, m + 1, dr, c)
    );
}

void zero_bad() {
    for (int i = 1; i <= n; ++i)
        for (int j = 1; j <= n; ++j)
            bad[i][j] = 0;
    return ;
}

int main() {
    //in.open("windows.in"); in >> n;
    cit(n);
    for (int i = 1; i <= n; ++i)
        for (int j = 1; j <= n; ++j)
            //in >> el[i][j];
            cit(el[i][j]);
    //in.close();
    
// full YOLO
    
    // Down
    
    for (int i = 1; i <= n; ++i)
        for (int j = 1; j <= n; ++j)
            if (el[i][j] == el[i][j - 1])
                bad[i][j] = true;
    for (int j = 1; j <= n; ++j)
        for (int i = n; i; --i) 
            if (bad[i][j] == 0)
                Down[i][j] = Down[i + 1][j] + 1;
            else
                Down[i][j] = 0;
    
    // Up
    zero_bad();
    for (int i = 1; i <= n; ++i)
        for (int j = 1; j <= n; ++j)
            if (el[i][j] == el[i][j + 1])
                bad[i][j] = true;
    for (int j = 1; j <= n; ++j)
        for (int i = 1; i <= n; ++i) 
            if (bad[i][j] == 0)
                Up[i][j] = Up[i - 1][j] + 1;
            else
                Up[i][j] = 0;
    
    // Left
    zero_bad();
    for (int i = 1; i <= n; ++i)
        for (int j = 1; j <= n; ++j)
            if (el[i][j] == el[i + 1][j])
                bad[i][j] = true;
    for (int i = 1; i <= n; ++i) 
        for (int j = 1; j <= n; ++j)
            if (bad[i][j] == 0)
                Left[i][j] = Left[i][j - 1] + 1;
            else
                Left[i][j] = 0;
                
    // Right
    zero_bad();
    for (int i = 1; i <= n; ++i)
        for (int j = 1; j <= n; ++j)
            if (el[i][j] == el[i - 1][j])
                bad[i][j] = true;
    for (int i = 1; i <= n; ++i) 
        for (int j = n; j; --j)
            if (bad[i][j] == 0)
                Right[i][j] = Right[i][j + 1] + 1;
            else
                Right[i][j] = 0;   
                
    // copy pasterino feederino
    for (int i = 1; i <= n; ++i)
        aint_Update(1, 1, n, i, inf);
    
    int rez = 0;
    
    /*for (int i = 1; i <= n; ++i, cerr << '\n')
        for (int j = 1; j <= n; ++j)
            cerr << el[i][j] << '\t';
    cerr << "\n\n";
    for (int i = 1; i <= n; ++i, cerr << '\n')
        for (int j = 1; j <= n; ++j)
            cerr << min(Up[i][j], Left[i][j]) << '\t';
    cerr << "\n\n";
    
    for (int i = 1; i <= n; ++i, cerr << '\n')
        for (int j = 1; j <= n; ++j)
            cerr << min(Down[i][j], Right[i][j]) << '\t';
    cerr << "\n\n";*/
    
    int T = 0;
    
    for (int i = 1; i <= n; ++i) {
        C1[++T] = i;
        L1[T] = 1;
    }
    for (int i = 2; i <= n; ++i) {
        C1[++T] = 1;
        L1[T] = i;
    }
    
    int lr, cr;
    
    for (int t = 1; t <= T; ++t) {
        int c = C1[t], l = L1[t];
        int st = 1, dr = 0;
        eventz = 0;
        for (int L = l + 1, C = c + 1; L <= n and C <= n; ++L, ++C) {
            int p = min(Right[L][C], Down[L][C]);
            if (p > 1) {
                event[++eventz] = make_pair(C, C);
                //if(C1[t] == c and L1[t] == l)
                    //event[++eventz] = make_pair(n, -C);
                //else   
                    event[++eventz] = make_pair(C + p, -C);
            }
        }  
        sort(event + 1, event + eventz + 1);
        int itr = 1;
        for (; l < n and c < n; ++l, ++c) {
            while (itr <= eventz and event[itr].first <= c) {
                int q = event[itr].second;
                if (q > 0) {
                    aint_Update(1, 1, n, q, q);
                } else {
                    aint_Update(1, 1, n, -q, inf);
                }
                ++itr;
            }
            
            int p = min(Up[l][c], Left[l][c]);
            int r = c - aint_query(1, 1, n, c - p + 1) + 1;
            if (rez < r or (rez == r and l * n + c < lr * n + cr)) {
                lr = l - r + 1;
                cr = c - r + 1;
                rez = r;
            }
        }
        while (itr <= eventz) {
                int q = event[itr].second;
                if (q > 0) {
                    aint_Update(1, 1, n, q, q);
                } else {
                    //cerr << q << '\n';
                    aint_Update(1, 1, n, -q, inf);
                }
                ++itr;
            }
    }
    //out.open("windows.out");
    if (rez == 0)
        //assert(0);
        cout << "-1\n";
    else
        cout << rez << ' ' << lr << ' ' << cr << '\n';
    //out.close();
    
    return 0;
}