#include <algorithm>
#include <cassert>
#include <cstdlib>
#include <iostream>
#include <random>
#include <set>
#include <utility>
#include <vector>

using namespace std;

// Compose independent boundary stress motifs. Each motif is designed to
// exercise a different way solutions can mishandle component boundaries.
//
// Default mode mixes four general motifs:
// - left summary traps depend on the minimum right endpoint,
// - right summary traps depend on the maximum left endpoint,
// - same-left and same-right motifs stress equality at the boundaries.
//
// Mono mode only uses strictly increasing left endpoints:
// - bridge traps stress tracking the maximum right endpoint after merges,
// - same-right stacks stress inclusive containment on equal right endpoints.
//
// Tiny mode only uses intervals of length 1 or 2:
// - forward chains stress adding a length-2 interval after its unit neighbors,
// - backward chains stress adding a unit interval after its length-2 containers.
//
// In both modes, the first block starts at L = 0 to catch off-by-one errors.

namespace {

void add_left_summary_trap(vector<pair<int, int>>& intervals, int base, int atoms, mt19937& rng) {
    for (int i = 0; i < atoms; i++) {
        intervals.push_back({base + 2 * i, base + 2 * i + 1});
    }

    intervals.push_back({base - 1, base + 2 * atoms});

    uniform_int_distribution<int> pick_span(0, atoms - 2);
    int span = pick_span(rng);
    intervals.push_back({base - 2, base + 2 * span + 1});
}

void add_right_summary_trap(vector<pair<int, int>>& intervals, int base, int atoms, mt19937& rng) {
    for (int i = 0; i < atoms; i++) {
        intervals.push_back({base + 2 * i, base + 2 * i + 1});
    }

    intervals.push_back({base - 1, base + 2 * atoms});

    uniform_int_distribution<int> pick_span(1, atoms - 1);
    int span = pick_span(rng);
    intervals.push_back({base + 2 * span, base + 2 * atoms + 1});
}

void add_same_left_motif(vector<pair<int, int>>& intervals, int base, int atoms, mt19937& rng) {
    for (int i = 0; i < atoms; i++) {
        intervals.push_back({base + 1 + 2 * i, base + 2 + 2 * i});
    }

    intervals.push_back({base, base + 2 * atoms + 1});

    uniform_int_distribution<int> pick_span(0, atoms - 2);
    int span = pick_span(rng);
    intervals.push_back({base, base + 2 * span + 2});
}

void add_same_right_motif(vector<pair<int, int>>& intervals, int base, int atoms, mt19937& rng) {
    for (int i = 0; i < atoms; i++) {
        intervals.push_back({base + 2 * i, base + 2 * i + 1});
    }

    intervals.push_back({base, base + 2 * atoms + 1});

    uniform_int_distribution<int> pick_span(1, atoms - 1);
    int span = pick_span(rng);
    intervals.push_back({base + 2 * span, base + 2 * atoms + 1});
}

int block_max_coord_general(int type, int base, int atoms) {
    if (type == 0) return base + 2 * atoms;
    return base + 2 * atoms + 1;
}

void add_block_general(vector<pair<int, int>>& intervals, int type, int base, int atoms, mt19937& rng) {
    if (type == 0) {
        add_left_summary_trap(intervals, base, atoms, rng);
    } else if (type == 1) {
        add_right_summary_trap(intervals, base, atoms, rng);
    } else if (type == 2) {
        add_same_left_motif(intervals, base, atoms, rng);
    } else {
        add_same_right_motif(intervals, base, atoms, rng);
    }
}

void add_mono_bridge_trap(vector<pair<int, int>>& intervals, int base, int atoms) {
    for (int i = 0; i < atoms; i++) {
        intervals.push_back({base + i, base + atoms + 1 + i});
    }

    intervals.push_back({base + atoms, base + atoms + 1});
    intervals.push_back({base + atoms + 1, base + 2 * atoms});
}

void add_mono_same_right_stack(vector<pair<int, int>>& intervals, int base, int atoms) {
    int right = base + atoms + 2;
    for (int i = 0; i < atoms + 2; i++) {
        intervals.push_back({base + i, right});
    }
}

int block_max_coord_mono(int type, int base, int atoms) {
    if (type == 0) return base + 2 * atoms;
    return base + atoms + 2;
}

void add_block_mono(vector<pair<int, int>>& intervals, int type, int base, int atoms) {
    if (type == 0) {
        add_mono_bridge_trap(intervals, base, atoms);
    } else {
        add_mono_same_right_stack(intervals, base, atoms);
    }
}

void add_tiny_forward_chain(vector<pair<int, int>>& intervals, int base, int atoms) {
    for (int i = 0; i <= atoms; i++) {
        intervals.push_back({base + i, base + i + 1});
    }
    for (int i = 0; i < atoms; i++) {
        intervals.push_back({base + i, base + i + 2});
    }
}

void add_tiny_backward_chain(vector<pair<int, int>>& intervals, int base, int atoms) {
    for (int i = 0; i < atoms; i++) {
        intervals.push_back({base + i, base + i + 2});
    }
    for (int i = 0; i <= atoms; i++) {
        intervals.push_back({base + i, base + i + 1});
    }
}

int block_max_coord_tiny(int base, int atoms) {
    return base + atoms + 1;
}

void add_block_tiny(vector<pair<int, int>>& intervals, int type, int base, int atoms) {
    if (type == 0) {
        add_tiny_forward_chain(intervals, base, atoms);
    } else {
        add_tiny_backward_chain(intervals, base, atoms);
    }
}

}  // namespace

int main(int argc, char* argv[]) {
    assert(argc == 4 || argc == 5);
    int N = atoi(argv[1]);
    int requested_blocks = atoi(argv[2]);
    int mode = 0;
    int seed = 0;
    if (argc == 4) {
        seed = atoi(argv[3]);
    } else {
        mode = atoi(argv[3]);
        seed = atoi(argv[4]);
    }
    assert(N >= 1);
    assert(mode == 0 || mode == 1 || mode == 2);

    if (N < 5) {
        cout << N << '\n';
        for (int i = 0; i < N; i++) {
            cout << 2 * i << ' ' << 2 * i + 1 << '\n';
        }
        return 0;
    }

    mt19937 rng(seed);

    int max_blocks = 1;
    int blocks = 1;
    vector<int> atoms_per_block;
    if (mode == 2) {
        max_blocks = max(1, N / 3);
        blocks = requested_blocks <= 0 ? 1 : min(requested_blocks, max_blocks);
        if ((blocks & 1) != (N & 1)) {
            if (blocks > 1) blocks--;
            else blocks++;
        }
        assert(1 <= blocks && blocks <= max_blocks);
        assert((blocks & 1) == (N & 1));

        atoms_per_block.assign(blocks, 1);
        int extra_atoms = (N - 3 * blocks) / 2;
        assert(extra_atoms >= 0);
        for (int i = 0; i < extra_atoms; i++) {
            atoms_per_block[(int)(rng() % (unsigned)blocks)]++;
        }
    } else {
        max_blocks = max(1, N / 5);
        blocks = requested_blocks <= 0 ? 1 : min(requested_blocks, max_blocks);

        atoms_per_block.assign(blocks, 3);
        int extra_atoms = N - 5 * blocks;
        for (int i = 0; i < extra_atoms; i++) {
            atoms_per_block[(int)(rng() % (unsigned)blocks)]++;
        }
    }
    shuffle(atoms_per_block.begin(), atoms_per_block.end(), rng);

    vector<int> block_types(blocks);
    if (mode == 0) {
        block_types[0] = (rng() & 1U) ? 2 : 3;
        for (int i = 1; i < blocks; i++) {
            block_types[i] = (int)(rng() % 4U);
        }
    } else if (mode == 1) {
        block_types[0] = 1;
        for (int i = 1; i < blocks; i++) {
            block_types[i] = (int)(rng() % 2U);
        }
    } else {
        block_types[0] = (int)(rng() % 2U);
        for (int i = 1; i < blocks; i++) {
            block_types[i] = (int)(rng() % 2U);
        }
    }

    vector<pair<int, int>> intervals;
    intervals.reserve((size_t)N);

    int base = 0;
    for (int i = 0; i < blocks; i++) {
        int type = block_types[i];
        int atoms = atoms_per_block[i];

        if (mode == 0 && i > 0 && (type == 0 || type == 1)) {
            base = max(base, 2);
        }

        if (mode == 0) {
            add_block_general(intervals, type, base, atoms, rng);
            base = block_max_coord_general(type, base, atoms) + 3;
        } else if (mode == 1) {
            add_block_mono(intervals, type, base, atoms);
            base = block_max_coord_mono(type, base, atoms) + 1;
        } else {
            add_block_tiny(intervals, type, base, atoms);
            base = block_max_coord_tiny(base, atoms) + 2;
        }
    }

    assert((int)intervals.size() == N);

    set<pair<int, int>> seen;
    int max_r = 0;
    for (auto interval : intervals) {
        assert(interval.first >= 0);
        assert(interval.first < interval.second);
        assert(seen.insert(interval).second);
        max_r = max(max_r, interval.second);
    }
    assert(max_r <= 2 * N);
    if (mode == 1) {
        for (int i = 1; i < N; i++) {
            assert(intervals[i - 1].first < intervals[i].first);
        }
    }
    if (mode == 2) {
        for (auto [l, r] : intervals) {
            assert(r - l <= 2);
        }
    }

    cout << N << '\n';
    for (auto [l, r] : intervals) {
        cout << l << ' ' << r << '\n';
    }
    return 0;
}
