#pragma comment(linker, "/STACK:512000000")
#include <bits/stdc++.h>
using namespace std;

#define all(a) a.begin(), a.end()
typedef long long li;
typedef long double ld;
void solve(__attribute__((unused)) bool);
void precalc();
clock_t start;
#define FILENAME ""

int main() {
#ifdef AIM
    string s = FILENAME;
//    assert(!s.empty());
    freopen("/home/alexandero/ClionProjects/cryptozoology/input.txt", "r", stdin);
#else
//    freopen(FILENAME ".in", "r", stdin);
//    freopen(FILENAME ".out", "w", stdout);
    //freopen("input.txt", "r", stdin);
    //freopen("output.txt", "w", stdout);
#endif
    start = clock();
    int t = 1;
#ifndef AIM
    cout.sync_with_stdio(0);
    cin.tie(0);
#endif
    precalc();
    cout.precision(10);
    cout << fixed;
    //cin >> t;
    int testNum = 1;
    while (t--) {
        //cout << "Case #" << testNum++ << ": ";
        solve(true);
    }
    cout.flush();
#ifdef AIM1
    while (true) {
      solve(false);
  }
#endif

#ifdef AIM
    cout.flush();
    auto end = clock();

    usleep(10000);
    print_stats(end - start);
    usleep(10000);
#endif

    return 0;
}

template<typename T>
T binpow(T q, T w, T mod) {
    if (!w)
        return 1 % mod;
    if (w & 1)
        return q * 1LL * binpow(q, w - 1, mod) % mod;
    return binpow(q * 1LL * q % mod, w / 2, mod);
}

template<typename T>
T gcd(T q, T w) {
    while (w) {
        q %= w;
        swap(q, w);
    }
    return q;
}
template<typename T>
T lcm(T q, T w) {
    return q / gcd(q, w) * w;
}

template <typename T>
void make_unique(vector<T>& a) {
    sort(all(a));
    a.erase(unique(all(a)), a.end());
}

template<typename T>
void relax_min(T& cur, T val) {
    cur = min(cur, val);
}

template<typename T>
void relax_max(T& cur, T val) {
    cur = max(cur, val);
}

void precalc() {
}

//#define int li
//const int mod = 1000000007;

void solve(__attribute__((unused)) bool read) {
    int n;
    cin >> n;
    vector<vector<int>> res(2 * n, vector<int>(2 * n, 0));
    vector<int> ds(2);
    cin >> ds[0] >> ds[1];
    for (int par1 = 0; par1 < 2; ++par1) {
        for (int par2 = 0; par2 < 2; ++par2) {
            for (int w = 0; w < 2; ++w) {
                vector<vector<int>> cur_res(2 * n, vector<int>(2 * n, 0));
                int d = ds[w];
                int step = 1;
                while (d % 4 == 0) {
                    step *= 2;
                    d /= 4;
                }
                if (d % 4 == 3) {
                    continue;
                }
                if (step > cur_res.size()) continue;
                if (d % 4 == 1) {
                    for (int i = 0; i * step < cur_res.size(); ++i) {
                        for (int j = 0; j * step < cur_res.size(); ++j) {
                            if ((i + j) % 2 == par1) {
                                cur_res[i][j] = 1;
                            }
                        }
                    }
                } else {
                    assert(d % 4 == 2);
                    for (int i = par2; i * step < cur_res.size(); i += 2) {
                        for (int j = 0; j * step < cur_res.size(); ++j) {
                            cur_res[i][j] = 1;
                        }
                    }
                }
                for (int i = 0; i < cur_res.size(); ++i) {
                    for (int j = 0; j < cur_res.size(); ++j) {
                        res[i][j] += cur_res[i / step][j / step];
                    }
                }
            }
            vector<pair<int, int>> ans;
            for (int i = 0; i < res.size(); ++i) {
                for (int j = 0; j < res.size(); ++j) {
                    if (res[i][j] == 2) {
                        ans.push_back({i, j});
                    }
                }
            }
            if (ans.size() >= n * n) {
                for (int i = 0; i < n * n; ++i) {
                    cout << ans[i].first << " " << ans[i].second << "\n";
                }
                return;
            }
        }
    }

    assert(false);


}

Measured memory_bytes: 3908