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: Time Limit Exceeded)

use std::collections::BTreeSet;

fn main() {
    let s = std::io::stdin();
    let mut sc = Scanner { reader: s.lock() };

    let n: usize = sc.read();
    let d1: usize = sc.read();
    let d2: usize = sc.read();

    let mut map = vec![vec![0; 2 * n]; 2 * n];
    let mut points = vec![];
    for i in 0..(2 * n) {
        for j in 0..(2 * n) {
            map[i][j] = points.len();
            points.push((i, j));
        }
    }

    let n = points.len();
    let mut graph1 = vec![vec![]; n];
    let mut graph2 = vec![vec![]; n];
    for from in 0..n {
        for dx in 0..n {
            if d1 >= dx * dx {
                let dy = ((d1 - dx * dx) as f64).sqrt().floor() as usize;
                add_edge(from, dx, dy, &mut graph1, &map, &points);
            }
            if d2 >= dx * dx {
                let dy = ((d2 - dx * dx) as f64).sqrt().floor() as usize;
                add_edge(from, dx, dy, &mut graph2, &map, &points);
            }
        }
    }

    let mut color1 = vec![0; n];
    color1[0] = 1;
    let result1 = coloring(0, &graph1, &mut color1);
    assert!(result1);

    let mut color2 = vec![0; n];
    color2[0] = 1;
    let result2 = coloring(0, &graph2, &mut color2);
    assert!(result2);

    let mut count = vec![vec![0; 2]; 2];
    for i in 0..n {
        count[color1[i] - 1][color2[i] - 1] += 1;
    }

    let (mut c1, mut c2) = (0, 0);
    for i in 0..2 {
        for j in 0..2 {
            if count[i][j] >= n / 4 {
                c1 = i + 1;
                c2 = j + 1;
                break;
            }
        }
    }

    assert!(c1 != 0);
    assert!(c2 != 0);
    let mut count = n / 4;
    for i in 0..n {
        if color1[i] == c1 && color2[i] == c2 {
            count -= 1;
            let (x, y) = points[i];
            println!("{} {}", x, y);
        }
        if count == 0 {
            break;
        }
    }

    assert_eq!(count, 0);
}

fn coloring(v: usize, graph: &Vec<Vec<usize>>, color: &mut Vec<usize>) -> bool {
    for &next in graph[v].iter() {
        if color[next] == 0 {
            color[next] = if color[v] == 1 { 2 } else { 1 };
            coloring(next, graph, color);
        } else if color[next] == color[v] {
            return false;
        }
    }
    true
}

fn add_edge(
    from: usize,
    dx: usize,
    dy: usize,
    graph: &mut Vec<Vec<usize>>,
    map: &Vec<Vec<usize>>,
    points: &Vec<(usize, usize)>,
) {
    let (x, y) = points[from];
    let x = x as i64;
    let y = y as i64;
    let dx = dx as i64;
    let dy = dy as i64;
    let next = vec![
        (x + dx, y + dy),
        (x - dx, y + dy),
        (x + dx, y - dy),
        (x - dx, y - dy),
    ];

    let mut to = BTreeSet::new();
    for &(x, y) in next.iter() {
        if x < 0 || y < 0 {
            continue;
        }

        let x = x as usize;
        let y = y as usize;
        if x >= map.len() || y >= map[x].len() {
            continue;
        }

        to.insert(map[x][y]);
    }

    for &to in to.iter() {
        graph[from].push(to);
    }
}

pub struct Scanner<R> {
    reader: R,
}

impl<R: std::io::Read> Scanner<R> {
    pub fn read<T: std::str::FromStr>(&mut self) -> T {
        use std::io::Read;
        let buf = self
            .reader
            .by_ref()
            .bytes()
            .map(|b| b.unwrap())
            .skip_while(|&b| b == b' ' || b == b'\n')
            .take_while(|&b| b != b' ' && b != b'\n')
            .collect::<Vec<_>>();
        unsafe { std::str::from_utf8_unchecked(&buf) }
            .parse()
            .ok()
            .expect("Parse error.")
    }
    pub fn read_vec<T: std::str::FromStr>(&mut self, n: usize) -> Vec<T> {
        (0..n).map(|_| self.read()).collect()
    }
    pub fn chars(&mut self) -> Vec<char> {
        self.read::<String>().chars().collect()
    }
}