#include <iostream>
#include <unordered_set>
#include <vector>
#include <algorithm>
#include <random>
#include <cassert>

using namespace std;

[[noreturn]] void usage()
{
    cerr << "Usage: ./generator seed mode n q max_x p ..." << endl;
    exit(1);
}

mt19937 r_dev;
mt19937_64 r_dev64;
// Returns a value in range [0, 1[
double rnd()
{
    return uniform_real_distribution<double>(0, 1)(r_dev);
}
// Returns a value in range [a, b] inclusive
int rnd(int a, int b)
{
    return uniform_int_distribution<int>(a, b)(r_dev);
}
long long rnd64(long long a, long long b)
{
    return uniform_int_distribution<long long>(a, b)(r_dev64);
}
// Returns either 0 or 1
int coin()
{
    return rnd(0, 1);
}
// Shuffles any type with begin and end
template <typename T>
void shuffle(T &arr)
{
    shuffle(arr.begin(), arr.end(), r_dev);
}

const int MAX_X = 1e9;

struct Instance {
    int n, q;
    vector<int> x, a, b;
    Instance(int n_, int q_) :
        n(n_), q(q_),
        x(n), a(q), b(q) {}

    void print() {
        cout << n << ' ' << q << '\n';
        for (int i = 0; i < n; ++i) {
            cout << x[i] << " \n"[i == n-1];
        }
        for (int i = 0; i < q; ++i) {
            cout << a[i] << ' ' << b[i] << '\n';
        }
    }

    // Shuffle or sort afterwards as needed!
    void random_values(int max_x) {
        if (max_x == MAX_X) {
            for (int i = 0; i < n; ++i) {
                x[i] = rnd(1, MAX_X);
            }
        } else if (max_x > 0) {
            // x arbitrary, but draw from max_x distinct values
            unordered_set<int> z;
            while ((int)z.size() < max_x) {
                z.insert(rnd(1, MAX_X));
            }
            vector<int> zv(z.begin(), z.end());
            for (int i = 0; i < n; ++i) {
                x[i] = zv[rnd(0, max_x-1)];
            }
        } else if (max_x == -1) {
            // Subtask 5: permutation
            iota(begin(x), end(x), 1);
        } else if (max_x == -2) {
            // Subtask 4: x <= 2
            for (int i = 0; i < n; ++i) x[i] = rnd(1, 2);
        } else {
            cerr << "max_x must be -1 or between 1 and n" << endl;
            exit(1);
        }
    }

    void random_queries(int prob_abgtn) {
        for (int i = 0; i < q; ++i) {
            if (rnd(0, 99) < prob_abgtn) {
                a[i] = rnd(1, n);
                b[i] = rnd(0, n);
                if (a[i] + b[i] <= n) {
                    a[i] = n+1 - a[i];
                    b[i] = n - b[i];
                }
            } else {
                a[i] = rnd(1, n);
                b[i] = rnd(1, n-1);
                if (a[i] + b[i] > n) {
                    a[i] = n+1 - a[i];
                    b[i] = n - b[i];
                }
            }
        }
    }

    void close_queries(int prob_abgtn, int max_gap, int a_min=1, int a_max=0) {
        if (a_max == 0) a_max = n;
        for (int i = 0; i < q; ++i) {
            if (rnd(0, 99) < prob_abgtn) {
                a[i] = rnd(a_min, a_max);
                b[i] = rnd(n-a[i]+1, min(n, n-a[i]+max_gap));
            } else {
                a[i] = rnd(a_min, min(n-1, a_max));
                b[i] = rnd(max(1, n-a[i]-max_gap+1), n-a[i]);
            }
            if (coin()) swap(a[i], b[i]);
        }
    }

    void random_swaps(int count) {
        for (int ci = 0; ci < count; ++ci) {
            int i = rnd(0, n-1), j = rnd(0, n-1);
            swap(x[i], x[j]);
        }
    }
};

int main(int argc, char **argv)
{
    // Check argument count
    if (argc < 7)
        usage();

    // Parse arguments into numbers
    unsigned long long seed = stoull(argv[1]);
    r_dev.seed(seed);
    r_dev64.seed(seed);
    string mode = argv[2];
    int n = atoi(argv[3]);
    int q = atoi(argv[4]);
    int max_x = atoi(argv[5]);          // -1 and -2 are special, otherwise number of unique x
    int p = atoi(argv[6]);              // percentage of queries with a + b > n

    if (n == 1 && p < 100) {
        cerr << "impossible: n = 1 and p < 100, but n = 1 always has a + b > n" << endl;
        return 1;
    }

    if (mode == "random") {
        Instance inst(n, q);
        inst.random_values(max_x);
        shuffle(inst.x);
        inst.random_queries(p);
        inst.print();
    } else if (mode == "blocks") {
        int block_count = atoi(argv[7]);    // number of blocks

        Instance inst(n, q);
        inst.random_values(max_x);

        vector<int> idx(n);
        iota(begin(idx), end(idx), 0);
        shuffle(idx);
        sort(begin(idx), begin(idx)+2*block_count);

        ranges::sort(inst.x);
        for (int i = 0; i < block_count; ++i)
            shuffle(begin(inst.x)+idx[2*i], begin(inst.x)+idx[2*i+1]+1, r_dev);

        inst.random_queries(p);
        inst.print();
    } else if (mode == "sorted") {
        Instance inst(n, q);
        inst.random_values(max_x);
        ranges::sort(inst.x);
        inst.random_queries(p);
        inst.print();
    } else if (mode == "high-ans") {
        Instance inst(n, q);
        inst.random_values(max_x);
        ranges::sort(inst.x, greater<>());
        inst.random_swaps(max(n/20, 1));
        inst.close_queries(p, 5);
        inst.print();
    } else if (mode == "xhigh-ans") {
        Instance inst(n, q);
        inst.random_values(max_x);
        ranges::sort(inst.x, greater<>());
        inst.random_swaps(max(n/40, 1));
        inst.close_queries(p, 3, 3*n/7, 4*n/7);
        inst.print();
    } else {
        cerr << "mode must be 'random', 'blocks', 'sorted' or '(x)high-ans'" << endl;
        return 1;
    }
}
