Problem:
Score : 800 points

Problem Statement

Takahashi is doing a research on sets of points in a plane.
Takahashi thinks a set S of points in a coordinate plane is a good set when S satisfies both of the following conditions:

The distance between any two points in S is not \sqrt{D_1}.

The distance between any two points in S is not \sqrt{D_2}.

Here, D_1 and D_2 are positive integer constants that Takahashi specified.

Let X be a set of points (i,j) on a coordinate plane where i and j are integers and satisfy 0 ≤ i,j < 2N.

Takahashi has proved that, for any choice of D_1 and D_2, there exists a way to choose N^2 points from X so that the chosen points form a good set.
However, he does not know the specific way to choose such points to form a good set.
Find a subset of X whose size is N^2 that forms a good set.

Constraints

1 ≤ N ≤ 300

1 ≤ D_1 ≤ 2×10^5

1 ≤ D_2 ≤ 2×10^5

All values in the input are integers.

Input

Input is given from Standard Input in the following format:

N D_1 D_2

Output

Print N^2 distinct points that satisfy the condition in the following format:

x_1 y_1
x_2 y_2
:
x_{N^2} y_{N^2}

Here, (x_i,y_i) represents the i-th chosen point.
0 ≤ x_i,y_i < 2N must hold, and they must be integers.
The chosen points may be printed in any order.
In case there are multiple possible solutions, you can output any.

Sample Input 1

2 1 2

Sample Output 1

0 0
0 2
2 0
2 2

Among these points, the distance between 2 points is either 2 or 2\sqrt{2}, thus it satisfies the condition.

Sample Input 2

3 1 5

Sample Output 2

0 0
0 2
0 4
1 1
1 3
1 5
2 0
2 2
2 4

Solution in Java8 (OpenJDK 1.8.0) (judge verdict: Time Limit Exceeded)

import java.io.OutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.util.List;
import java.util.StringTokenizer;
import java.util.Random;
import java.io.IOException;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.io.InputStream;

/**
 * Built using CHelper plug-in
 * Actual solution is at the top
 */
public class Main {
	public static void main(String[] args) {
		InputStream inputStream = System.in;
		OutputStream outputStream = System.out;
		FastScanner in = new FastScanner(inputStream);
		PrintWriter out = new PrintWriter(outputStream);
		ProblemD solver = new ProblemD();
		solver.solve(1, in, out);
		out.close();
	}

	static class ProblemD {
		public void solve(int testNumber, FastScanner in, PrintWriter out) {
			int n = in.nextInt();
			int d1 = in.nextInt();
			int d2 = in.nextInt();
			List<Point> forbidden = new ArrayList<>();
			for (int x = -2 * n; x <= 2 * n; x++) {
				for (int y = -2 * n; y <= 2 * n; y++) {
					Point p = new Point(x, y);
					int d = x * x + y * y;
					if (d == d1 || d == d2) {
						forbidden.add(p);
					}
				}
			}

			Random random = new Random(0);
			int k = 0;
			boolean[][] used = new boolean[2 * n][2 * n];

			while (k < n * n) {
				int bestX = 0;
				int bestY = 0;
				int bestBad = -1;
				int bestR = 0;
				for (int it = 0; it < 30; it++) {
					int x = random.nextInt(2 * n);
					int y = random.nextInt(2 * n);
					while (used[x][y]) {
						x = random.nextInt(2 * n);
						y = random.nextInt(2 * n);
					}
					int bad = 0;
					for (Point p : forbidden) {
						int nx = x + p.x;
						int ny = y + p.y;
						if (nx >= 0 && nx < 2 * n && ny >= 0 && ny < 2 * n && used[nx][ny]) {
							++bad;
						}
					}
					int dx = x - n;
					int dy = y - n;
					int r = dx * dx + dy * dy;
//				int r = Math.max(Math.abs(dx), Math.abs(dy));
//				if (bestBad < 0 || bestBad > bad || bestBad == bad && bestR < r) {
					if (bestBad < 0 || bestBad > bad) {
						bestBad = bad;
						bestX = x;
						bestY = y;
						bestR = r;
					}
					if (bestBad == 0) {
						break;
					}
				}
				int x = bestX;
				int y = bestY;
				for (Point p : forbidden) {
					int nx = x + p.x;
					int ny = y + p.y;
					if (nx >= 0 && nx < 2 * n && ny >= 0 && ny < 2 * n && used[nx][ny]) {
						--k;
						used[nx][ny] = false;
					}
				}
				++k;
				used[x][y] = true;
			}

			for (int x = 0; x < 2 * n; x++) {
				for (int y = 0; y < 2 * n; y++) {
					if (used[x][y]) {
						out.println(x + " " + y);
					}
				}
			}
		}

		class Point {
			int x;
			int y;

			Point(int x, int y) {
				this.x = x;
				this.y = y;
			}

		}

	}

	static class FastScanner {
		private BufferedReader in;
		private StringTokenizer st;

		public FastScanner(InputStream stream) {
			in = new BufferedReader(new InputStreamReader(stream));
		}

		public String next() {
			while (st == null || !st.hasMoreTokens()) {
				try {
					String rl = in.readLine();
					if (rl == null) {
						return null;
					}
					st = new StringTokenizer(rl);
				} catch (IOException e) {
					throw new RuntimeException(e);
				}
			}
			return st.nextToken();
		}

		public int nextInt() {
			return Integer.parseInt(next());
		}

	}
}