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: Wrong Answer)

// https://atcoder.jp/contests/agc025/tasks/agc025_d
//
#![allow(unused_imports)]
use std::io::*;
use std::fmt::*;
use std::str::*;
use std::cmp::*;
use std::collections::*;

macro_rules! input {
    (source = $s:expr, $($r:tt)*) => {
        let mut iter = $s.split_whitespace();
        input_inner!{iter, $($r)*}
    };
    ($($r:tt)*) => {
        let s = {
            use std::io::Read;
            let mut s = String::new();
            std::io::stdin().read_to_string(&mut s).unwrap();
            s
        };
        let mut iter = s.split_whitespace();
        input_inner!{iter, $($r)*}
    };
}

macro_rules! input_inner {
    ($iter:expr) => {};
    ($iter:expr, ) => {};

    ($iter:expr, $var:ident : $t:tt $($r:tt)*) => {
        let $var = read_value!($iter, $t);
        input_inner!{$iter $($r)*}
    };
}

macro_rules! read_value {
    ($iter:expr, ( $($t:tt),* )) => {
        ( $(read_value!($iter, $t)),* )
    };

    ($iter:expr, [ $t:tt ; $len:expr ]) => {
        (0..$len).map(|_| read_value!($iter, $t)).collect::<Vec<_>>()
    };

    ($iter:expr, chars) => {
        read_value!($iter, String).chars().collect::<Vec<char>>()
    };

    ($iter:expr, usize1) => {
        read_value!($iter, usize) - 1
    };

    ($iter:expr, $t:ty) => {
        $iter.next().unwrap().parse::<$t>().expect("Parse error")
    };
}

#[allow(unused_macros)]
macro_rules! debug {
    ($($a:expr),*) => {
        println!(concat!($(stringify!($a), " = {:?}, "),*), $($a),*);
    }
}

fn get(a: &Vec<Vec<i32>>, i: usize, j: usize, x: i64, y: i64) -> i32 {
    let i = i as i64 + x;
    let j = j as i64 + y;
    let n = a.len() as i64;
    if i < 0 || j < 0 || i >= n || j >= n {
        return 0;
    }
    return a[i as usize][j as usize];
}

fn set(a: &mut Vec<Vec<i32>>, i: usize, j: usize, x: i64, y: i64, v: i32) {
    let i = i as i64 + x;
    let j = j as i64 + y;
    let n = a.len() as i64;
    if i < 0 || j < 0 || i >= n || j >= n {
        return;
    }
    a[i as usize][j as usize] = v;
}

fn generate(n: usize, d: i64) -> Vec<Vec<i32>> {
    let mut sqrt_table = vec![-1; n];
    for i in 0..n {
        let i2 = i * i;
        if i2 < n {
            sqrt_table[i2] = i as i64;
        }
    }

    let mut ds: Vec<(i64, i64)> = vec![];
    for x in 0..n+1 {
        let xi = x as i64;
        let y2 = d - xi * xi;
        if y2 < 0 {
            continue;
        }
        if y2 >= sqrt_table.len() as i64 {
            continue;
        }
        let yi = sqrt_table[y2 as usize];
        if yi == -1 {
            continue;
        }
        ds.push((xi, yi));
    }


    let mut field = vec![vec![0; n]; n];
    for i in 0..n {
        for j in 0..n {
            let mut has_left = field[i][j] == -1;
            let mut has_right = field[i][j] == 1;
            for &(x, y) in &ds {
                let a = get(&field, i, j, x, y);
                if a == 1 {
                    has_left = true;
                } else if a == -1 {
                    has_right = true;
                }
            }
            let mut tset = 1;
            if has_left {
                field[i][j] = -1;
                tset = 1;
            } else {
                field[i][j] = 1;
                tset = -1;
            }
            for &(x, y) in &ds {
                set(&mut field, i, j, x, y, tset);
                set(&mut field, i, j, -x, y, tset);
                set(&mut field, i, j, x, -y, tset);
                set(&mut field, i, j, -x, -y, tset);
            }

        }
    }
    field
}

fn main() {
    input! {
        n: usize, d1: i64, d2: i64
    };

    let graph1 = generate(2*n, d1);
    let graph2 = generate(2*n, d2);

    let mut table = vec![vec![0; 2*n]; 2*n];
    for i in 0..2*n {
        for j in 0..2*n {
            let a = if graph1[i][j] == 1 { 0 } else { 1 };
            let b = if graph2[i][j] == 1 { 0 } else { 2 };
            table[i][j] = a+b;
        }
    }


    let mut cnt = vec![0; 4];
    let mut wx = 0;
    for i in 0..2*n {
        for j in 0..2*n {
            cnt[table[i][j]] += 1;
            if cnt[table[i][j]] > cnt[wx] {
                wx = table[i][j];
            }
        }
    }

    let mut cnt = 0;
    for i in 0..2*n {
        for j in 0..2*n {
            if table[i][j] == wx {
                cnt += 1;
                if cnt <= n*n {
                    println!("{} {}", i, j);
                }
            }
        }
    }
}