#include <bits/stdc++.h>
using namespace std;
typedef bool boolean;

const int N = 1e3 + 5;

#define pii pair<int, int>

int n, d1, d2;
vector<pii> ans;

void solve(int d1, int d2, int k, int rx, int ry) {
	int r1 = d1 % 4, r2 = d2 % 4;

	static auto flip = [&] (boolean (*a)[2]) {
		for (int i = 0; i < 2; i++) {
			a[i][0] = !a[i][0];
			a[i][1] = !a[i][1];
		}
	};
	if (!r1 && !r2) {
		solve(d1 >> 2, d2 >> 2, k << 1, rx << 1, ry << 1);
		solve(d1 >> 2, d2 >> 2, k << 1, rx << 1 | 1, ry << 1);
		solve(d1 >> 2, d2 >> 2, k << 1, rx << 1, ry << 1 | 1);
		solve(d1 >> 2, d2 >> 2, k << 1, rx << 1 | 1, ry << 1 | 1);
	} else if (!r1 && r2) {
		int _d1 = d1, m = 1;
		while (!(_d1 % 4))
			m <<= 1, _d1 >>= 2;
		int _r1 = (_d1 % 4);
		boolean sec2[2][2], sec1[2][2];
		memset(sec1, false, sizeof(sec1));
		memset(sec2, false, sizeof(sec2));
		if (r2 == 1) {
			sec2[0][0] = sec2[1][1] = true;
		} else if (r2 == 2) {
			sec2[0][0] = sec2[0][1] = true;
		} else if (r2 == 3) {
			memset(sec2, true, sizeof(sec2));
		}
		if (_r1 == 1) {
			sec1[0][0] = sec1[1][1] = true;
		} else if (_r1 == 2) {
			sec1[0][0] = sec1[0][1] = true;
		} else if (_r1 == 3) {
			memset(sec1, true, sizeof(sec1));
		}

		vector<pii> res, tmp;

		auto work = [&] () {
			tmp.clear();
			for (int i = rx; i < n * 2; i += k) {
				for (int j = ry; j < n * 2; j += k) {
					int gx1 = ((i - rx) / k) / m;
					int gy1 = ((j - ry) / k) / m;
					int gx2 = ((i - rx) / k) % m;
					int gy2 = ((j - ry) / k) % m;
					if (sec1[gx1 & 1][gy1 & 1] && sec2[gx2 & 1][gy2 & 1]) {
						tmp.emplace_back(i, j);
					}
				}
			}
			if (tmp.size() > res.size()) {
				res = tmp;
			}
		};

		work();
		flip(sec1);
		work();
		flip(sec2);
		work();
		flip(sec1);
		work();

		for (auto x : res) {
			ans.push_back(x);
		}
	} else if (r1 && !r2) {
		int _d2 = d2, m = 1;
		while (!(_d2 % 4))
			m <<= 1, _d2 >>= 2;

		int _r2 = _d2 % 4;
		boolean sec2[2][2], sec1[2][2];
		memset(sec1, false, sizeof(sec1));
		memset(sec2, false, sizeof(sec2));
		if (_r2 == 1) {
			sec2[0][0] = sec2[1][1] = true;
		} else if (_r2 == 2) {
			sec2[0][0] = sec2[0][1] = true;
		} else if (_r2 == 3) {
			memset(sec2, true, sizeof(sec2));
		}
		if (r1 == 1) {
			sec1[0][0] = sec1[1][1] = true;
		} else if (r1 == 2) {
			sec1[0][0] = sec1[0][1] = true;
		} else if (r1 == 3) {
			memset(sec1, true, sizeof(sec1));
		}
		
		vector<pii> res, tmp;
		auto work = [&] () {
			tmp.clear();
			for (int i = rx; i < n * 2; i += k) {
				for (int j = ry; j < n * 2; j += k) {
					int gx1 = ((i - rx) / k) % m;
					int gy1 = ((j - ry) / k) % m;
					int gx2 = ((i - rx) / k) / m;
					int gy2 = ((j - ry) / k) / m;
					if (sec1[gx1 & 1][gy1 & 1] && sec2[gx2 & 1][gy2 & 1]) {
						tmp.emplace_back(i, j);
					}
				}
			}
			if (tmp.size() > res.size()) {
				res = tmp;
			}
		};

		work();
		flip(sec1);
		work();
		flip(sec2);
		work();
		flip(sec1);
		work();

		for (auto x : res) {
			ans.push_back(x);
		}
	} else {
		for (int i = rx; i < n * 2; i += k) {
			for (int j = ry; j < n * 2; j += k) {
				int x = (i - rx) / k;
				int y = (j - ry) / k;
				if (!(x & 1) && !(y & 1)) {
					ans.emplace_back(i, j);
				}
			}
		}
	}
}

int main() {
	scanf("%d%d%d", &n, &d1, &d2);
//	srand((unsigned) time (NULL));
//	n = rand() % 10 + 1;
//	int V = n * n * 2;
//	d1 = rand() % V + 1;
//	d2 = rand() % V + 1;
	solve(d1, d2, 1, 0, 0);
	assert((signed) ans.size() >= n * n);
	for (int i = 0; i < n * n; i++) {
		printf("%d %d\n", ans[i].first, ans[i].second);
	}
	return 0;
	for (auto x : ans) {
		for (auto y : ans) {
			int d = (x.first - y.first) * (x.first - y.first) + (x.second - y.second) * (x.second - y.second);
			assert(d != d1 && d != d2);
		}
	}
	return 0;
}



Measured memory_bytes: 3444