#include <bits/stdc++.h>
using namespace std;

static constexpr int G = 6;
static constexpr int P = 5;
static constexpr int N = G * P;
static constexpr int W = 6;

struct Group {
    uint32_t mask = 0;
    array<int, P> v{};
    uint64_t pairmask[2]{}; // 435 pairs, split into two words is not enough; kept unused.
    array<pair<int,int>, 10> pairs{};
};

static vector<Group> candidates;
static uint8_t used[N][N];
static vector<vector<int>> weeks(W);
static mt19937_64 rng;
static chrono::steady_clock::time_point deadline;
static long long nodes = 0;
static long long part_nodes = 0;

static int pair_index(int a, int b) {
    if (a > b) swap(a, b);
    return a * N + b;
}

static bool time_ok() {
    return chrono::steady_clock::now() < deadline;
}

static bool group_ok(const Group& gr) {
    for (auto [a, b] : gr.pairs) {
        if (used[a][b]) return false;
    }
    return true;
}

static void apply_group(const Group& gr, int delta) {
    for (auto [a, b] : gr.pairs) {
        used[a][b] += delta;
        used[b][a] += delta;
    }
}

static Group make_group(vector<int> xs) {
    sort(xs.begin(), xs.end());
    Group gr;
    for (int i = 0; i < P; ++i) {
        gr.v[i] = xs[i];
        gr.mask |= 1u << xs[i];
    }
    int k = 0;
    for (int i = 0; i < P; ++i) {
        for (int j = i + 1; j < P; ++j) {
            gr.pairs[k++] = {xs[i], xs[j]};
        }
    }
    return gr;
}

static bool add_fixed_group(int w, vector<int> xs) {
    Group gr = make_group(xs);
    if (!group_ok(gr)) return false;
    int id = (int)candidates.size();
    candidates.push_back(gr);
    apply_group(candidates[id], 1);
    weeks[w].push_back(id);
    return true;
}

static void build_fixed_two_weeks() {
    memset(used, 0, sizeof(used));
    weeks.assign(W, {});
    candidates.clear();

    for (int r = 0; r < G; ++r) {
        vector<int> xs;
        for (int c = 0; c < P; ++c) xs.push_back(r * P + c);
        if (!add_fixed_group(0, xs)) abort();
    }

    // Canonical second week: group m misses first-week row m. In each row,
    // the five players are labelled by the group they join among the five
    // groups that do not miss that row.
    for (int miss = 0; miss < G; ++miss) {
        vector<int> xs;
        for (int r = 0; r < G; ++r) {
            if (r == miss) continue;
            int c = miss < r ? miss : miss - 1;
            xs.push_back(r * P + c);
        }
        if (!add_fixed_group(1, xs)) abort();
    }
}

static void build_candidates() {
    int base = (int)candidates.size();
    for (int miss = 0; miss < G; ++miss) {
        vector<int> rows;
        for (int r = 0; r < G; ++r) if (r != miss) rows.push_back(r);
        for (int a = 0; a < P; ++a)
        for (int b = 0; b < P; ++b)
        for (int c = 0; c < P; ++c)
        for (int d = 0; d < P; ++d)
        for (int e = 0; e < P; ++e) {
            int cs[P] = {a,b,c,d,e};
            vector<int> xs;
            for (int i = 0; i < P; ++i) xs.push_back(rows[i] * P + cs[i]);
            Group gr = make_group(xs);
            if (group_ok(gr)) candidates.push_back(gr);
        }
    }
    cerr << "candidates=" << candidates.size() - base << "\n";
}

static vector<int> current_valid_candidates(uint32_t rem) {
    vector<int> out;
    out.reserve(candidates.size());
    for (int id = 12; id < (int)candidates.size(); ++id) {
        const Group& gr = candidates[id];
        if ((gr.mask & rem) != gr.mask) continue;
        if (group_ok(gr)) out.push_back(id);
    }
    return out;
}

static bool can_finish_week(uint32_t rem) {
    if (!rem) return true;
    int possible[N]{};
    for (int id = 12; id < (int)candidates.size(); ++id) {
        const Group& gr = candidates[id];
        if ((gr.mask & rem) == gr.mask && group_ok(gr)) {
            uint32_t m = gr.mask;
            while (m) {
                int b = __builtin_ctz(m);
                possible[b]++;
                m &= m - 1;
            }
        }
    }
    uint32_t m = rem;
    while (m) {
        int b = __builtin_ctz(m);
        if (!possible[b]) return false;
        m &= m - 1;
    }
    return true;
}

static bool suffix_possible(int week) {
    // Cheap player-level capacity: every remaining player needs 5 new partners
    // per remaining week, all among currently unused pairs.
    int remaining_weeks = W - week;
    for (int a = 0; a < N; ++a) {
        int free = 0;
        for (int b = 0; b < N; ++b) if (a != b && !used[a][b]) ++free;
        if (free < remaining_weeks * (P - 1)) return false;
    }
    return true;
}

static bool rec_week(int week, uint32_t rem) {
    ++nodes;
    if ((nodes & 0xffff) == 0) {
        if (!time_ok()) return false;
        cerr << "nodes=" << nodes << " week=" << week << " rem=" << __builtin_popcount(rem) << "\n";
    }
    if (week == W) return true;
    if (rem == 0) {
        if (!suffix_possible(week + 1)) return false;
        return rec_week(week + 1, (1u << N) - 1);
    }

    vector<int> ids;
    int best_player = -1;
    int best_count = INT_MAX;
    uint32_t tm = rem;
    while (tm) {
        int p = __builtin_ctz(tm);
        int cnt = 0;
        for (int id = 12; id < (int)candidates.size(); ++id) {
            const Group& gr = candidates[id];
            if (!((gr.mask >> p) & 1u)) continue;
            if ((gr.mask & rem) == gr.mask && group_ok(gr)) ++cnt;
        }
        if (cnt < best_count) {
            best_count = cnt;
            best_player = p;
        }
        tm &= tm - 1;
    }
    if (best_player < 0 || best_count == 0) return false;

    for (int id = 12; id < (int)candidates.size(); ++id) {
        const Group& gr = candidates[id];
        if (!((gr.mask >> best_player) & 1u)) continue;
        if ((gr.mask & rem) != gr.mask) continue;
        if (!group_ok(gr)) continue;
        ids.push_back(id);
    }

    shuffle(ids.begin(), ids.end(), rng);
    sort(ids.begin(), ids.end(), [&](int a, int b) {
        auto score = [&](int id) {
            const Group& gr = candidates[id];
            int s = 0;
            uint32_t m = rem & ~gr.mask;
            while (m) {
                int p = __builtin_ctz(m);
                int cnt = 0;
                for (int cid = 12; cid < (int)candidates.size(); ++cid) {
                    const Group& cg = candidates[cid];
                    if (!((cg.mask >> p) & 1u)) continue;
                    if ((cg.mask & m) == cg.mask && group_ok(cg)) ++cnt;
                }
                s += min(cnt, 50);
                m &= m - 1;
            }
            return s;
        };
        return score(a) < score(b);
    });

    for (int id : ids) {
        const Group& gr = candidates[id];
        apply_group(gr, 1);
        weeks[week].push_back(id);
        if (can_finish_week(rem & ~gr.mask) && rec_week(week, rem & ~gr.mask)) return true;
        weeks[week].pop_back();
        apply_group(gr, -1);
    }
    return false;
}

static bool validate() {
    uint8_t cnt[N][N]{};
    for (int w = 0; w < W; ++w) {
        uint32_t seen = 0;
        for (int id : weeks[w]) {
            const Group& gr = candidates[id];
            if (seen & gr.mask) return false;
            seen |= gr.mask;
            for (auto [a,b] : gr.pairs) {
                if (++cnt[a][b] > 1) return false;
                cnt[b][a] = cnt[a][b];
            }
        }
        if (seen != ((1u << N) - 1)) return false;
    }
    return true;
}

int main(int argc, char** argv) {
    int seconds = argc > 1 ? atoi(argv[1]) : 300;
    uint64_t seed = argc > 2 ? strtoull(argv[2], nullptr, 10) : 1;
    rng.seed(seed);
    deadline = chrono::steady_clock::now() + chrono::seconds(seconds);

    long long restarts = 0;
    while (time_ok()) {
        ++restarts;
        build_fixed_two_weeks();
        build_candidates();
        nodes = 0;
        if (rec_week(2, (1u << N) - 1) && validate()) {
            cerr << "solution restarts=" << restarts << " nodes=" << nodes << "\n";
            for (int w = 0; w < W; ++w) {
                cout << "week " << w << "\n";
                for (int id : weeks[w]) {
                    const Group& gr = candidates[id];
                    for (int i = 0; i < P; ++i) {
                        if (i) cout << ' ';
                        cout << gr.v[i];
                    }
                    cout << "\n";
                }
            }
            return 0;
        }
        cerr << "restart " << restarts << " nodes=" << nodes << "\n";
    }
    cerr << "no solution restarts=" << restarts << " nodes=" << nodes << "\n";
    return 1;
}
