Problem:
Score : 900 points

Problem Statement

Let us consider a grid of squares with N rows and N columns. You want to put some domino pieces on this grid.
Each domino piece covers two squares that have a common side. Each square can be covered by at most one piece.

For each row of the grid, let's define its quality as the number of domino pieces that cover at least one square in this row.
We define the quality of each column similarly.

Find a way to put at least one domino piece on the grid so that the quality of every row is equal to the quality of every column,
or determine that such a placement doesn't exist.

Constraints

2 \le N \le 1000

Input

Input is given from Standard Input in the following format:

N

Output

If the required domino placement doesn't exist, print a single integer -1.

Otherwise, output your placement as N strings of N characters each.
If a square is not covered, the corresponding character must be . (a dot).
Otherwise, it must contain a lowercase English letter.
Squares covered by the same domino piece must contain the same letter.
If two squares have a common side but belong to different pieces, they must contain different letters.

Sample Input 1

6

Sample Output 1

aabb..
b..zz.
ba....
.a..aa
..a..b
..a..b

The quality of every row and every column is 2.

Sample Input 2

2

Sample Output 2

-1

Solution in C++14 (GCC 5.4.1) (judge verdict: Wrong Answer)

#ifndef ENV_AC
    #define ENV_AC
    #include <stdio.h>
    #include <stdlib.h>
    #include <assert.h>
    #include <fstream>
    #include <iostream>
    #include <sstream>
    #include <iomanip>
    #include <algorithm>
    #include <bitset>
    #include <array>
    #include <vector>
    #include <queue>
    #include <set>
    #include <cmath> // 変数名にy1が使えなくなるかも…。
    #include <map>
    #include <unordered_map>
    #include <unordered_set>
    #include <limits>
    #include <functional>
    #include <string>
    #include <ext/rope>

    using int128_t = __int128_t;
    std::istream &operator>>(std::istream& input, int128_t& value) { // int128_tの入力。入力が64bitに収まる前提。
        int64_t tmp; input >> tmp; value = tmp;
        return input;
    }
    std::ostream &operator<<(std::ostream& output, const int128_t value) { // int128_tの出力。出力が64bitに収まる前提。
        output << (int64_t)value;
        return output;
    }

    namespace std {
        template<> class hash<int128_t>{
            public:
            size_t operator () ( const int128_t &x ) const {
                int64_t INF64 = std::numeric_limits<int64_t>::max();
                int64_t y1 = x / INF64;
                int64_t y2 = x % INF64;
                return hash<int64_t>()(y1) ^ hash<int64_t>()(y2);
            }
        };
    }

    int128_t imax(const int128_t a, const int128_t b) { return std::max(a, b); } // std::max, std::min は型が違うとエラーになるため、ラッパーを作る。
    int128_t imin(const int128_t a, const int128_t b) { return std::min(a, b); }
    int128_t iabs(const int128_t x) { return 0 <= x ? x : -x; }
    int128_t ipow(const int128_t x, const int128_t n) { int128_t ret = 1; for (int i = 0; i < n; i++) { ret *= x; } return ret; } // 1 << d みたいな書き方は、dが32以上だと困るので、ipow(2,d)を使う。

    int128_t bitcheck(const int128_t bit, const int128_t pos) {
        return (bit >> pos) & 1;
    }
    int128_t bitcount64(const int128_t bit) {
        int ret = 0;
        for (int i = 0; i < 64; i++) {
            ret += bitcheck(bit, i);
        }
        return ret;
    }

    template <int128_t mod> class Mod_Int {
        public:
        int128_t val;

        void calc() {
            if (val < 0) { val += ((iabs(val) + mod) / mod) * mod; }
            val %= mod;
        }
        Mod_Int(const int128_t _val = 0) { val = _val; calc(); }
        int128_t INT() { return val; } // 使用は非想定
        int128_t MOD() { return mod; } // 使用は非想定
        Mod_Int operator-() const { return Mod_Int(-val); }
        Mod_Int operator+(const Mod_Int &r) const { return Mod_Int(val + r.val); }
        Mod_Int operator-(const Mod_Int &r) const { return Mod_Int(val - r.val); }
        Mod_Int operator*(const Mod_Int &r) const { return Mod_Int(val * r.val); }
        //Mod_Int operator/(const Mod_Int &r) const { return ; } // ユークリッド互除法を使うべきだが保留。
        Mod_Int& operator+=(const Mod_Int &r) { val += r.val; calc(); return *this; }
        Mod_Int& operator-=(const Mod_Int &r) { val -= r.val; calc(); return *this; }
        Mod_Int& operator*=(const Mod_Int &r) { val *= r.val; calc(); return *this; }
        Mod_Int& operator++() { return (*this) += 1; }
        Mod_Int& operator--() { return (*this) -= 1; }
        Mod_Int operator++(int) { Mod_Int tmp = *this; ++*this; return tmp; }
        Mod_Int operator--(int) { Mod_Int tmp = *this; --*this; return tmp; }
        bool operator==(const Mod_Int &r) const { return val == r.val; }
        bool operator!=(const Mod_Int &r) const { return val != r.val; }

        friend std::istream &operator>>(std::istream& input, Mod_Int& r) { 
            int128_t tmp; input >> tmp;
            r = Mod_Int(tmp);
            return input;
        }
        friend std::ostream &operator<<(std::ostream& output, const Mod_Int& r) { 
            output << r.val;
            return output;
        }
    };

    struct Closed_Section {
        bool valid;
        int128_t begin;
        int128_t end;
        Closed_Section(bool _valid, int128_t _begin, int128_t _end) {
            valid = _valid; begin = _begin; end = _end;
        }
        Closed_Section() {
            valid = false, begin = 0; end = -1;
        }
        int128_t size() { return valid ? end - begin + 1 : 0; }
        Closed_Section operator*(const Closed_Section &r) const {
            if (!valid) { return Closed_Section(valid, begin, end); }
            if (!r.valid) { return r; }
            if (end < r.begin) { return Closed_Section(false, 0, -1); }
            if (r.end < begin) { return Closed_Section(false, 0, -1); }
            return Closed_Section(true, std::max(begin, r.begin), std::min(end, r.end));
        }
        void dump() { std::cout << "valid:" << valid << " begin:" << begin << " end:" << end << std::endl; }
    };

    //template<class Fn> Closed_Section binary_search(int128_t L, int128_t R, Fn func) {
    Closed_Section binary_search(const int128_t L, const int128_t R, std::function<bool(int128_t)> func) {
        if (R < L) { return Closed_Section(false, L, R); }
        const bool res_L = func(L);
        const bool res_R = func(R);
        if (res_L && res_R) {
            return Closed_Section(true, L, R);
        } else if (!res_L && !res_R) {
            return Closed_Section(false, 0, -1);
        } else {
            int128_t lb = L;
            int128_t ub = R;
            while (lb + 1 < ub) {
                int128_t mid = (lb + ub) / 2;
                if (res_L == func(mid)) {
                    lb = mid;
                } else {
                    ub = mid;
                }
            }
            return res_L ? Closed_Section(true, L, lb) : Closed_Section(true, ub, R);
        }
    }

    Closed_Section binary_search(const Closed_Section& cs, std::function<bool(int128_t)> func) {
        return cs.valid ? binary_search(cs.begin, cs.end, func) : cs;
    }

    #define rep(i, begin, end) for(int64_t i = ((int128_t)begin); i <= ((int128_t)end); i++) // (int128_t)end としておくと、end = v.size() - 2 みたいな入力で、v.size()が1でも正常(end = -1になる）に挙動する。end = 2 - v.size() - 1のような入力でも、int128_tであれば計算がint128_tで進行する（intやint64_tだと途中でsize_tになってしまう。）。
    #define rev(i, begin, end) for(int64_t i = ((int128_t)begin); ((int128_t)end) <= i; i--) // int128_tにすると、3重ループでコンパイルエラーになることがあった（再現性は不明）ので変数はint64_tにしておく。

    #define input1(begin, end, v1) v1.resize((end)+1); for (int itr = (begin); itr <= (end); itr++) { std::cin >> v1[itr]; }
    #define input2(begin, end, v1, v2) v1.resize((end)+1); v2.resize((end)+1); for (int itr = (begin); itr <= (end); itr++) { std::cin >> v1[itr] >> v2[itr]; } 
    #define input3(begin, end, v1, v2, v3) v1.resize((end)+1); v2.resize((end)+1); v3.resize((end)+1); for (int itr = (begin); itr <= (end); itr++) { std::cin >> v1[itr] >> v2[itr] >> v3[itr]; }
    #define input4(begin, end, v1, v2, v3, v4) v1.resize((end)+1); v2.resize((end)+1); v3.resize((end)+1); v4.resize((end)+1); for (int i = (begin); i <= (end); i++) { std::cin >> v1[i] >> v2[i] >> v3[i] >> v4[i]; } 
    #define input5(begin, end, v1, v2, v3, v4, v5) v1.resize((end)+1); v2.resize((end)+1); v3.resize((end)+1); v4.resize((end)+1); v5.resize((end)+1); for (int i = (begin); i <= (end); i++) { std::cin >> v1[i] >> v2[i] >> v3[i] >> v4[i] >> v5[i]; }  
    // input_arrayはbegin = 0のときのみ動作確認。Aの要素の型をテンプレートにして関数にしたほうが丁寧かもしれない。
    #define input_array(begin, N, M, A) A.resize((begin)+(N)); for (int i = 0; i < (begin)+(N); i++) { A[i].resize((begin)+(M)); } for (int i = begin; i < (begin)+(N); i++) { for (int j = begin; j < (begin)+(M); j++) { std::cin >> A[i][j]; }}

    std::vector<int128_t> irange(const int128_t begin, const int128_t end) {
        std::vector<int128_t> ret; for (int128_t i = begin; i <= end; i++) { ret.push_back(i); }
        return ret;
    }

    template <typename T>
    std::vector<T> accumulate_vec(const std::vector<T>& vec, const bool reverse = false) {
        std::vector<T> ret; ret.resize(vec.size());
        if (0 < vec.size()) {
            if (reverse == false) {
                ret[0] = vec[0];
                for (int i = 1; i < ret.size(); i++) {
                    ret[i] = ret[i-1] + vec[i];
                }
            } else {
                ret[ret.size()-1] = vec[ret.size()-1];
                for (int i = ret.size() - 2; 0 <= i; i--) {
                    ret[i] = ret[i+1] + vec[i];
                }
            }
        }
        return ret;
    }

    template <typename T>
    void sort_vec(
        std::vector<T>& vec, int128_t begin, int128_t end, 
        std::function<bool(T, T)> func = [&](const T& a, const T& b) { return a < b; }
    ) {
        std::sort(vec.begin() + begin, vec.begin() + end + 1, func);
    }

    template <typename T>
    T cal_pow(T x, int128_t n, T tmp = T(1)) {
        // 累乗の計算。
        while (n > 0) {
            if (n & 1) { tmp = tmp * x; }
            x = x * x;
            n = (n >> 1);
        }
        return tmp;
    }

    std::vector<int128_t> digit(int128_t n, const int128_t b) {
        // 基数bでの表示。0は0桁。非常に大きい数を入れても問題ないようにint128_tとする。
        // size()をとれば桁数になる。
        assert(1 < b);
        std::vector<int128_t> ret;
        while (0 < n) {
            ret.push_back(n % b);
            n /= b;
        }
        return ret;
    }

    template <typename T>
    void printvec(const std::vector<T>& vec) {
        for (int i = 0; i < vec.size(); i++) { std::cout << vec[i] << " "; } std::cout << std::endl;
    }
#endif


//--code begin--

int128_t N;
//std::vector<int128_t> a, b;
//std::string S_in;
std::vector<std::string> ret;
//double A, B, H, W;
//std::vector<double> ;

//const int128_t MAX_N = 20;
//const int128_t MOD = 1e9 + 7;
//const int128_t INF = std::numeric_limits<int64_t>::max(); const int128_t NEG_INF = std::numeric_limits<int64_t>::min();
//using pair = std::pair<int128_t, int128_t>;
//using mnt = Mod_Int<MOD>;


//std::map<pair, pair> mp[4];



int main(int argc, char **argv) {
    std::cin.tie(0);
   	std::ios::sync_with_stdio(false);
    std::cout << std::fixed << std::setprecision(15);

    std::cin >> N;
    
    if (N % 3 != 0) {
        std::cout << -1 << std::endl;
        return 0;
    }

    ret.resize(N);
    rep (i, 0, N - 1) {
        rep (j, 0, N - 1) {
            ret[i].push_back('.');
        }
    }

    rep (i, 0, N - 1) {
        rep (j, 0, N - 1) {
            if (i % 3 == 0 && j % 3 < 2) {
                ret[i][j] = 'a';
            }
            if (j % 3 == 2 && i % 3 != 0) {
                ret[i][j] = 'b';
            }
        }
    }

    rep (i, 0, N - 1) {
        std::cout << ret[i] << std::endl;
    }


    return 0;
}