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)

use std::io::*;
use std::str::FromStr;

#[allow(dead_code)]
fn read<T: FromStr>() -> T {
    let stdin = stdin();
    let stdin = stdin.lock();
    let token: String = stdin
        .bytes()
        .map(|c| c.expect("failed to read char") as char)
        .skip_while(|c| c.is_whitespace())
        .take_while(|c| !c.is_whitespace())
        .collect();
    token.parse().ok().expect("failed to parse token")
}

fn dfs(
    y: usize,
    x: usize,
    xy: &Vec<(i32, i32)>,
    color: i32,
    visit: &mut Vec<Vec<i32>>,
    usable: &Vec<Vec<bool>>,
) -> (i32, i32) {
    let n = visit.len() / 2;
    assert!(visit[y][x] == -1);
    assert!(usable[y][x]);
    visit[y][x] = color;
    let mut ret = (color ^ 1, color);
    for &(dx, dy) in xy.iter() {
        let nx = x as i32 + dx;
        let ny = y as i32 + dy;
        if nx < 0 || nx >= n as i32 * 2 || ny < 0 || ny >= n as i32 * 2 {
            continue;
        }
        let nx = nx as usize;
        let ny = ny as usize;
        if visit[ny][nx] != -1 || !usable[ny][nx] {
            continue;
        }
        let nret = dfs(ny, nx, xy, color ^ 1, visit, usable);
        ret.0 += nret.0;
        ret.1 += nret.1;
    }
    ret
}

fn solve(n: usize, ds: Vec<i32>) {
    let mut usable = vec![vec![true; 2 * n]; 2 * n];
    for &d in ds.iter() {
        let mut xy = vec![];
        for x in 0..d + 1 {
            if x * x > d {
                break;
            }
            let rest = d - x * x;
            let y = (rest as f64).sqrt() as i32;
            if y * y == rest {
                xy.push((x, y));
                xy.push((-x, y));
                xy.push((x, -y));
                xy.push((-x, -y));
            }
        }
        xy.sort();
        xy.dedup();
        let mut visit = vec![vec![-1; 2 * n]; 2 * n];
        let mut cnt = (0, 0);
        for y in 0..2 * n {
            for x in 0..2 * n {
                if !usable[y][x] || visit[y][x] != -1 {
                    continue;
                }
                let ncnt = dfs(y, x, &xy, 0, &mut visit, &usable);
                cnt.0 += ncnt.0;
                cnt.1 += ncnt.1;
            }
        }
        let ban_color = if cnt.0 < cnt.1 { 0 } else { 1 };
        // println!("{:?} {}", cnt, ban_color);
        for y in 0..2 * n {
            for x in 0..2 * n {
                if visit[y][x] == ban_color {
                    usable[y][x] = false;
                }
            }
        }
    }
    let mut anss = vec![];
    'yloop: for y in 0..2 * n {
        for x in 0..2 * n {
            if usable[y][x] {
                anss.push((x, y));
                if anss.len() == n * n {
                    break 'yloop;
                }
            }
        }
    }

    // println!("{} {}", anss.len(), n * n);
    assert!(anss.len() == n * n);
    for i in 0..n * n {
        println!("{} {}", anss[i].0, anss[i].1);
    }
}

fn main() {
    let n = read::<usize>();
    let mut ds = vec![0; 2];
    ds[0] = read::<i32>();
    ds[1] = read::<i32>();
    solve(n, ds);
}

#[test]
fn search_xy() {
    {
        for d in 1..100 {
            let mut xy = vec![];
            for x in 0..d + 1 {
                if x * x > d {
                    break;
                }
                let rest = d - x * x;
                let y = (rest as f64).sqrt() as usize;
                if y * y == rest {
                    xy.push((x, y));
                }
            }
            println!("{} {} {:?}", d, xy.len(), xy);
        }
    }
}

#[test]
fn search() {
    for n in 1..30 {
        for d1 in 1..30 {
            for d2 in d1 + 1..30 {
                println!("{} {} {}", n, d1, d2);
                solve(n, vec![d1, d2]);
            }
        }
    }
}