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 C++14 (GCC 5.4.1) (judge verdict: Wrong Answer)

#include <iostream>
#include <fstream>
#include <sstream>
#include <iomanip>
#include <vector>
#include <string>
#include <algorithm>
#include <queue>
#include <stack>
#include <map>
#include <set>
#include <unordered_set>
#include <unordered_map>
#include <bitset>
#include <limits>
#include <random>
#include <complex>
#include <cmath>
#include <cstdio>
#include <cstdlib>
using namespace std;

#define REP(i,n) for(int (i)=0;(i)<(int)(n);(i)++)
#define RREP(i,n) for(int (i)=(int)(n)-1;i>=0;i--)
#define REMOVE(Itr,n) (Itr).erase(remove((Itr).begin(),(Itr).end(),n),(Itr).end())
typedef long long ll;

struct XorShift {
    unsigned int x;
    XorShift () : x(2463534242U) {}
    unsigned int rand() {
        x ^= (x << 13);
        x ^= (x >> 17);
        x ^= (x << 5);
        return x;
    }
} Random;

struct Timer {

    double CYCLE_PER_SEC = 2800000000.0;
    unsigned long long BEGIN_CYCLE = 0;

    Timer() {}
    Timer(double cycle) : CYCLE_PER_SEC(cycle) {}

    unsigned long long int getCycle() {
        unsigned int low, high;
        __asm__ volatile ("rdtsc" : "=a" (low), "=d" (high));
        return ((unsigned long long int)low) | ((unsigned long long int)high << 32);
    }

    void start(void) {
        BEGIN_CYCLE = getCycle();
    }

    double get_time(void) {
        return (double)(getCycle() - BEGIN_CYCLE) / CYCLE_PER_SEC;
    }

} timer;

const double TIME_LIMIT = 1.8;
const double TEMP_START = 10.0;
const double TEMP_END   = 0.001;
const double TEMP_DIFF  = (TEMP_START - TEMP_END) / TIME_LIMIT;

ll N;
ll D1,D2;

ll score;
ll best_score;
vector < pair < int,int > > ans;
vector < pair < int,int > > non_used;
vector < pair < int,int > > best_ans;
vector < pair < int,int > > diff_cnd;

bool used[610][610];

ll get_diff (pair < int,int > pre, pair < int,int > nxt) {
	ll ret = 0;
	REP(i,diff_cnd.size()) {
		int x = pre.first + diff_cnd[i].first;
		int y = pre.second + diff_cnd[i].second;
		if (x < 0 || y < 0 || x >= 2 * N || y >= 2 * N) continue;
		if (used[x][y]) ret--;
	}
	used[pre.first][pre.second] = false;
	REP(i,diff_cnd.size()) {
		int x = nxt.first + diff_cnd[i].first;
		int y = nxt.second + diff_cnd[i].second;
		if (x < 0 || y < 0 || x >= 2 * N || y >= 2 * N) continue;
		if (used[x][y]) ret++;
	}
	used[pre.first][pre.second] = true;
	return -ret;
}

bool accept (double diff, double temp) {
    if (diff >= 0) return true;
    double P = exp(diff / temp) * 4294967295.0;
    return Random.rand() < P;
}

void simulated_annealing () {
	int cnt = 0;
	while (true) {
		REP(i,ans.size()) {
			double cur_time = timer.get_time();
			double cur_temp = TEMP_START - TEMP_DIFF * cur_time;
			if (cur_time > TIME_LIMIT) return;
			int r = Random.rand() % non_used.size();
			ll diff = get_diff(ans[i], non_used[r]);
			if (accept((double) diff, cur_temp)) {
				used[ans[i].first][ans[i].second] = false;
				used[non_used[r].first][non_used[r].second] = true;
				swap(ans[i].first, non_used[r].first);
				swap(ans[i].second, non_used[r].second);
				score -= diff;
				if (best_score > score) {
					best_score = score;
					best_ans = ans;
				}
			}
		}
	}
}

int main() {

	timer.start();

	cin >> N >> D1 >> D2;

	set < pair < int,int > > koho;
	for (int i = 0; i <= D1; i++) {
		int A = i;
		int B = D1 - i;
		int sqA = (int) sqrt(A);
		int sqB = (int) sqrt(B);
		if (A != sqA * sqA) continue;
		if (B != sqB * sqB) continue;
		koho.insert(make_pair(sqA, sqB));
		koho.insert(make_pair(-sqA, sqB));
		koho.insert(make_pair(sqA, -sqB));
		koho.insert(make_pair(-sqA, -sqB));
	}
	for (int i = 0; i <= D2; i++) {
		int A = i;
		int B = D2 - i;
		int sqA = (int) sqrt(A);
		int sqB = (int) sqrt(B);
		if (A != sqA * sqA) continue;
		if (B != sqB * sqB) continue;
		koho.insert(make_pair(sqA, sqB));
		koho.insert(make_pair(-sqA, sqB));
		koho.insert(make_pair(sqA, -sqB));
		koho.insert(make_pair(-sqA, -sqB));
	}

	for (auto itr : koho) {
		diff_cnd.push_back(itr);
	}

	REP(i,N * N) {
		used[i / N][i % N] = true;
		ans.push_back(make_pair(i / N, i % N));
	}

	REP(i,2*N) REP(j,2*N) {
		if (!used[i][j]) {
			non_used.push_back(make_pair(i, j));
		}
	}

	REP(i,ans.size()) {
		REP(j,diff_cnd.size()) {
			int x = ans[i].first + diff_cnd[j].first;
			int y = ans[i].second + diff_cnd[j].second;
			if (x < 0 || y < 0 || x >= 2 * N || y >= 2 * N) continue;
			if (used[x][y]) score++;
		}
	}

	score /= 2;
	best_score = score;
	best_ans = ans;

	simulated_annealing();

	REP(i,best_ans.size()) {
		cout << best_ans[i].first << " " << best_ans[i].second << endl;
	}

	return 0;
}