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++ (GCC 5.4.1) (judge verdict: Accepted)

#include<bits/stdc++.h>
using namespace std;
int n;
int D1,D2;
int get(int x,int y){return x*(n*2)+y;}
struct data{
    int to,nxt;
};
struct Graph{
    data mp[20000200];
    int head[500500],cnt;
    void link(int x,int y)
    {
        mp[++cnt].to=y;
        mp[cnt].nxt=head[x];
        head[x]=cnt;
    }
    int fl[2020][2],tf;
    int c[500500];
    void dfs(int x,int d)
    {
        c[x]=d;
        for(int i=head[x];i;i=mp[i].nxt)
            if(c[mp[i].to]==-1)
                dfs(mp[i].to,d^1);
    }
    void build(int D)
    {
        for(int i=0,j;i*i<=D;++i)
        {
            j=sqrt(D-i*i);
            if(i*i+j*j!=D)continue;
            fl[++tf][0]=i;fl[tf][1]=j;
            fl[++tf][0]=i;fl[tf][1]=-j;
            fl[++tf][0]=-i;fl[tf][1]=j;
            fl[++tf][0]=-i;fl[tf][1]=-j;
        }
        int u,x,y;
        for(int i=0;i<n*2;++i)
            for(int j=0;j<n*2;++j)
            {
                u=get(i,j);
                for(int p=1;p<=tf;++p)
                {
                    x=i+fl[p][0];y=j+fl[p][1];
                    if(x<0||x>=n*2||y<0||y>=n*2)continue;
                    link(u,get(x,y));
                }
            }
        memset(c,-1,sizeof(c));
        for(int i=0;i<n*2;++i)
            for(int j=0;j<n*2;++j)
                if(c[get(i,j)]==-1)dfs(get(i,j),0);
    }
}g1,g2;
int cnt[2][2];
int main()
{
    scanf("%d%d%d",&n,&D1,&D2);
    g1.build(D1);
    g2.build(D2);
    int x;
    for(int i=0;i<n*2;++i)
        for(int j=0;j<n*2;++j)
        {
            x=get(i,j);
            cnt[g1.c[x]][g2.c[x]]++;
        }
    int ou=1;
    for(int i=0;i<2&&ou<=n*n;++i)
        for(int j=0;j<2&&ou<=n*n;++j)
        {
            if(cnt[i][j]<n*n)continue;
            for(int p=0;p<n*2&&ou<=n*n;++p)
                for(int q=0;q<n*2&&ou<=n*n;++q)
                {
                    x=get(p,q);
                    if(g1.c[x]==i&&g2.c[x]==j)
                    {
                        ou++;
                        printf("%d %d\n",p,q);
                    }
                }
        }
    return 0;
}