//#pragma GCC optimize("Ofast,unroll-loops")
//#pragma GCC target("avx2,tune=native")
#include <bits/stdc++.h>
using namespace std;
 
#define file "graph"
#define ff(i, a, b) for(auto i=(a); i<=(b); ++i)
#define ffr(i, b, a) for(auto i=(b); i>=(a); --i)
#define nl "\n"
#define ss " "
//#define pb push_back
#define pb emplace_back
#define fi first
#define se second
#define sz(s) (int)s.size()
#define all(s) (s).begin(), (s).end()
#define ms(a,x) memset(a, x, sizeof (a))
#define cn continue
#define re exit(0)
 
typedef long long ll;
typedef unsigned long long ull;
typedef long double ld;
typedef vector<int> vi;
typedef vector<ll> vll;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
typedef vector<pii> vpii;
typedef vector<pll> vpll;
 
mt19937_64 rng(chrono::steady_clock::now().time_since_epoch().count());
ll ran(ll l, ll r)
{
    return uniform_int_distribution<ll> (l, r)(rng);
}
 
inline void rf()
{
    ios_base::sync_with_stdio(false);
    cin.tie(nullptr); cout.tie(nullptr);
    if(fopen(file".inp","r"))
    {
        freopen(file".inp","r",stdin);
        freopen(file".out","w",stdout);
    }
}
 
const int mod=1e9+19972207;
const int maxn=1e5+15;
const ll inf=5e16;
 
template<typename T> inline void add(T &x, const T &y)
{
    x+=y;
    if(x>=mod) x-=mod;
    if(x<0) x+=mod;
}
 
template<typename T> inline bool maxi(T &a, T b)
{
    if(a>=b) return 0;
    a=b; return 1;
}
 
template<typename T> inline bool mini(T &a, T b)
{
    if(a<=b) return 0;
    a=b; return 1;
}
 
// Khai báo các biến toàn cục
int diss, numPair;
int numNode;
vector<pair<int, int>> edges;
// Hết khai báo các biến toàn cục
 
void init(void) {
    cin >> diss >> numPair;
}
 
void print(void) {
    cout << numNode << " " << edges.size() << "\n";
    for (const pair<int, int> &e : edges) cout << e.fi << " " << e.se << "\n";
}
 
namespace general {
    bool check(void) {
        return diss > 2;
    }
 
    void createComponent(int x, int y) {
        // Tạo đường đi P gồm diss cạnh (diss+1 đỉnh)
        // P_1 -- P_2 -- ... -- P_{diss+1}. Khoảng cách P_1-P_{diss+1} là diss.
        // P_1 là left_center, P_{diss+1} là right_center.
 
        int left_center = ++numNode;
        int cur = left_center;
        ff(i, 1, diss) {
            int tmp = ++numNode;
            edges.push_back({cur, tmp});
            cur = tmp;
        }
        int right_center = cur;
 
        // Đính x lá vào left_center và y lá vào right_center
        ff(i, 1, x) edges.push_back({left_center, ++numNode});
        ff(i, 1, y) edges.push_back({right_center, ++numNode});
 
        // Tổng số đỉnh thêm: (diss + 1) + x + y
        // Tổng số cạnh thêm: diss + x + y
    }
 
    void solve(void) {
        while (numPair > 0) {
            // Số đỉnh cần cho 1 TPLT: (diss + 1) + x + y
            int N_required_min = diss + 1 + 2; // (diss+1) + 1 + 1 (cho x=y=1)
 
            // Giới hạn số đỉnh còn lại
            int N_remain = 1000 - numNode;
            if (N_remain < N_required_min) break;
 
            // Giới hạn về số cạnh còn lại
            int M_remain = 1000 - (int)edges.size();
 
            // Tìm t tối ưu (Cauchy) sao cho t*t <= numPair
            int current_t = (int)sqrt(numPair);
 
            // Giới hạn t bởi số đỉnh: (diss + 1) + 2*t <= N_remain => 2*t <= N_remain - (diss + 1)
            int limit_t_N = (N_remain - (diss + 1)) / 2;
            if (limit_t_N < 1) limit_t_N = 1;
 
            // Giới hạn t bởi số cạnh: diss + 2*t <= M_remain => 2*t <= M_remain - diss
            int limit_t_M = (M_remain - diss) / 2;
            if (limit_t_M < 1) limit_t_M = 1;
 
            int limit_t = min(limit_t_N, limit_t_M);
 
            int t = min(current_t, limit_t);
            if (t < 1) t = 1;
 
            int x, y;
            if (t * t <= numPair) {
                x = t;
                y = t;
            } else { // Trường hợp numPair rất nhỏ
                x = 1;
                y = numPair; // Sẽ xử lý giới hạn ngay dưới đây
            }
 
            // Nếu x=t, y=t vượt quá giới hạn đỉnh/cạnh, ta phải dùng x và y khác
            if (numNode + (diss + 1) + x + y > 1000 || edges.size() + diss + x + y > 1000) {
                // Ta phải dùng x=1 (tối thiểu), và y tối đa có thể
                x = 1;
 
                // Giới hạn y bởi số đỉnh: (diss + 1) + 1 + y <= N_remain
                int limit_y_N = N_remain - (diss + 1) - 1;
                if (limit_y_N < 1) limit_y_N = 1;
 
                // Giới hạn y bởi số cạnh: diss + 1 + y <= M_remain
                int limit_y_M = M_remain - diss - 1;
                if (limit_y_M < 1) limit_y_M = 1;
 
                y = min({numPair, limit_y_N, limit_y_M});
 
                if (y < 1) { // Không thể thêm bất kỳ cặp nào
                    break;
                }
            }
 
            // Nếu x*y > numPair (chỉ xảy ra khi ta dùng limit_t > current_t, hoặc x=1, y=numPair)
            if (x * y > numPair) {
                // Nếu x=t, y=t. Ta phải tìm x và y sao cho x*y <= numPair, x+y nhỏ nhất
                x = (int)sqrt(numPair);
                y = numPair / x;
 
                // Kiểm tra lại giới hạn
                if (numNode + (diss + 1) + x + y > 1000 || edges.size() + diss + x + y > 1000) {
                    // Nếu vẫn vượt giới hạn, dùng x=1, y=numPair giới hạn bởi 1000
                    x = 1;
                    int limit_y = min({1000 - numNode - (diss + 2), 1000 - (int)edges.size() - diss - 1});
                    y = min(numPair, limit_y);
                }
            }
 
            if (x > 0 && y > 0) {
                createComponent(x, y);
                numPair -= x * y;
            } else {
                break;
            }
        }
    }
}
 
namespace special {
    bool check(void) {
        return diss == 2;
    }
 
    void createComponent(int t) {
        // Tạo ra TPLT có 1 đỉnh u nối với t đỉnh khác (v1, ..., vt).
        // Khoảng cách giữa các cặp (vi, vj) là 2. Có t*(t-1)/2 cặp.
 
        int u = ++numNode;
        ff(i, 1, t) edges.push_back({u, ++numNode});
 
        // Tổng số đỉnh thêm: 1 + t
        // Tổng số cạnh thêm: t
    }
 
    void solve(void) { 
        while (numPair > 0) {
            // Tìm t tối ưu: t*(t-1)/2 <= numPair
            int t = 2;
            while ((ll)(t + 1) * t / 2 <= numPair) t++;
            t--;
 
            // Số đỉnh cần cho 1 TPLT: 1 + t
            int N_remain = 1000 - numNode;
            if (N_remain < 1 + 2) break; // Cần ít nhất 3 đỉnh (t=2)
 
            // Giới hạn về số cạnh còn lại
            int M_remain = 1000 - (int)edges.size();
 
            // Giới hạn t bởi số đỉnh: 1 + t <= N_remain
            int limit_t_N = N_remain - 1;
 
            // Giới hạn t bởi số cạnh: t <= M_remain
            int limit_t_M = M_remain;
 
            int limit_t = min(limit_t_N, limit_t_M);
 
            t = min(t, limit_t);
            if (t < 2) t = 2; // Cần t >= 2 để có cặp đỉnh khoảng cách 2
 
            // Nếu t*(t-1)/2 > numPair (chỉ xảy ra khi ta dùng limit_t > t_Cauchy)
            if ((ll)t * (t - 1) / 2 > numPair) {
                // Ta phải tìm t sao cho t*(t-1)/2 <= numPair và t nhỏ nhất
                t = 2;
                while ((ll)(t + 1) * t / 2 <= numPair) t++;
                t--;
                // Sau đó giới hạn lại theo limit_t
                t = min(t, limit_t);
                if (t < 2) t = 2;
            }
 
            // Nếu t vẫn quá nhỏ (t=1) thì không tạo được cặp nào
            if (t < 2) break;
 
            ll pairs_created = (ll)t * (t - 1) / 2;
            if (pairs_created > 0) {
                createComponent(t);
                numPair -= pairs_created;
            } else {
                break;
            }
        }
    }
}
 
void process(void) {
    if (general::check()) {
        general::solve();
    } else if (special::check()) {
        special::solve();
    }
}
 
signed main()
{
    rf();
    init();
    process();
    print();
    //re; // Bỏ re; để chương trình kết thúc bình thường
    return 0;
}