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 Rust (1.15.1) (judge verdict: Accepted)

#[allow(unused_imports)]
use std::cmp::{min,max};
#[allow(unused_imports)]
use std::collections::{BTreeMap,BTreeSet};
#[allow(unused_imports)]
use std::ops::*;
#[allow(unused_imports)]
use std::collections::BinaryHeap;

#[allow(unused_macros)]
macro_rules! tf {
    ($c:expr, $t:expr, $f:expr) => {{
        if $c { $t } else { $f }
    }};
}

fn dfs(field: &mut Vec<Vec<Option<bool>>>, ds: &Vec<(i64,i64)>, y: usize, x: usize, c: bool) {
    let n = field.len() / 2;
    if field[y][x].is_some() {
        return;
    }
    field[y][x] = Some(c);
    for &(dy,dx) in ds {
        let ny = y as i64 + dy;
        let nx = x as i64 + dx;
        if 0 <= ny && ny < 2*n as i64 && 0 <= nx && nx < 2*n as i64 {
            let ny = ny as usize;
            let nx = nx as usize;
            dfs(field, ds, ny, nx, !c);
        }
    }
}

fn main() {
    let (n, d1, d2) = {
        let xs = read_vec_i64();
        (xs[0] as usize, xs[1], xs[2])
    };
    let mut field1 = vec![vec![None; 2*n]; 2*n];
    let mut field2 = vec![vec![None; 2*n]; 2*n];
    let mut d1s = vec![];
    let mut d2s = vec![];
    for i in 0..2*n as i64 {
        for k in 0..2*n as i64 {
            if i * i + k * k == d1 {
                d1s.push((i,k));
                d1s.push((-i,k));
                d1s.push((i,-k));
                d1s.push((-i,-k));
            }
            if i * i + k * k == d2 {
                d2s.push((i,k));
                d2s.push((-i,k));
                d2s.push((i,-k));
                d2s.push((-i,-k));
            }
        }
    }
    for i in 0..2*n {
        for k in 0..2*n {
            dfs(&mut field1, &d1s, i, k, false);
            dfs(&mut field2, &d2s, i, k, false);
        }
    }
    let mut xs = vec![vec![]; 4];
    for y in 0..2*n {
        for x in 0..2*n {
            let t1 = field1[y][x].unwrap();
            let t2 = field2[y][x].unwrap();
            let i = tf!(t1, 2, 0) + tf!(t2, 1, 0);
            xs[i].push((y, x));
        }
    }
    for i in 0..4 {
        if xs[i].len() >= n * n {
            for &(y,x) in xs[i].iter().take(n*n) {
                println!("{} {}", x, y);
            }
            break;
        }
    }
}

#[allow(dead_code)]
fn read_line() -> String {
    let mut ret = String::new();
    std::io::stdin().read_line(&mut ret).ok();
    ret.pop();
    //ret.pop();
    return ret;
}

#[allow(dead_code)]
fn read_i64() -> i64 {
    let ss = read_line();
    return ss.parse::<i64>().unwrap();
}

#[allow(dead_code)]
fn read_vec_i64() -> Vec<i64> {
    let mut res = vec![];
    let ss = read_line();
    for ts in ss.split_whitespace() {
        let x = ts.parse::<i64>().unwrap();
        res.push(x);
    }
    return res;
}

use std::fmt::Display;
#[allow(dead_code)]
fn write_vec<T: Display>(xs: &Vec<T>) {
    if xs.len() == 0 {
        println!("");
        return;
    }
    print!("{}", xs[0]);
    for i in 1..xs.len() {
        print!(" {}", xs[i]);
    }
    println!("");
}