#include <iostream>
#include <vector>
#include <algorithm>


using namespace std;


long long gcd(long long a, long long b) {
    while (b) { a %= b; swap(a, b); }
    return a;
}


long long lcm(long long a, long long b) {
    return (a / gcd(a, b)) * b;
}


bool solveBinPacking(const vector<int>& pieces, vector<int>& bins, int target, int index) {
    if (index == pieces.size()) return true;
   
    for (int j = 0; j < bins.size(); ++j) {
        if (bins[j] + pieces[index] <= target) {
            bins[j] += pieces[index];
            if (solveBinPacking(pieces, bins, target, index + 1)) return true;
            bins[j] -= pieces[index];
        }
        if (bins[j] == 0) break;
    }
    return false;
}


bool canDivide(vector<int> pieces, int k, int target) {
    if (k == 1) return true;
   
    sort(pieces.rbegin(), pieces.rend());
    if (pieces[0] > target) return false;


    vector<int> bins(k, 0);
    return solveBinPacking(pieces, bins, target, 0);
}


// KHAI BÁO BIẾN LƯU TRỮ KẾT QUẢ TỔNG KẾT
vector<vector<int>> valid_configs;
long long total_checked = 0;


void generateAndFilterPartitions(int remaining, int current_min, vector<int>& current, int m, int n, int i_max) {
    int slots_left = m - current.size();
   
    int max_possible_piece = n / i_max;
    if (remaining > slots_left * max_possible_piece) return;


    if (slots_left <= 0 && remaining > 0) return;


    // KHI ĐÃ ĐIỀN ĐỦ M PHẦN TỬ VÀ TỔNG BẰNG N
    if (remaining == 0 && slots_left == 0) {
        total_checked++;
        bool isValid = true;
       
        // Kiểm tra điều kiện
        for (int k = i_max; k >= 2; --k) {
            if (!canDivide(current, k, n / k)) {
                isValid = false;
                break;
            }
        }
       
        // IN RA TERMINAL THEO THỜI GIAN THỰC
        cout << "(";
        for (size_t j = 0; j < current.size(); ++j) {
            cout << current[j];
            if (j < current.size() - 1) cout << ",";
        }
        cout << ") " << (isValid ? "NHAN GIA TRI NAY" : "") << "\n";
       
        // Nếu hợp lệ, lưu trữ lại để in tổng kết
        if (isValid) {
            valid_configs.push_back(current);
        }
        return;
    }


    int upper_bound = min(remaining, max_possible_piece);
    for (int val = current_min; val <= upper_bound; ++val) {
        current.push_back(val);
        generateAndFilterPartitions(remaining - val, val, current, m, n, i_max);
        current.pop_back();
    }
}


int main() {
    int i_max, m;
    cout << "Nhap so khach toi da i (tu 1 den i): ";
    if (!(cin >> i_max)) return 0;
   
    long long n = 1;
    for (int k = 1; k <= i_max; ++k) {
        n = lcm(n, k);
    }
    cout << "=> Da tinh Mau so chung (LCM) n = " << n << "\n";


    cout << "Nhap so manh banh m can kiem tra: ";
    if (!(cin >> m)) return 0;


    cout << "\nDang kiem tra tung phan hoach...\n";
    cout << "--------------------------------\n";
   
    vector<int> current;
    current.reserve(m);
   
    // Bắt đầu sinh và in real-time
    generateAndFilterPartitions(n, 1, current, m, n, i_max);


    // PHẦN TỔNG KẾT CUỐI CÙNG
    cout << "--------------------------------\n";
    cout << "Da kiem tra tong cong: " << total_checked << " cau hinh.\n";
    cout << "So cau hinh THOA MAN: " << valid_configs.size() << "\n\n";
   
    if (!valid_configs.empty()) {
        cout << "DANH SACH CAC CAU HINH NHAN:\n";
        for (size_t i = 0; i < valid_configs.size(); ++i) {
            cout << "Bo " << i + 1 << ": (";
            for (size_t j = 0; j < valid_configs[i].size(); ++j) {
                cout << valid_configs[i][j];
                if (j < valid_configs[i].size() - 1) cout << ",";
            }
            cout << ")\n";
        }
    } else {
        cout << "Khong co cau hinh nao thoa man!\n";
    }
   
    return 0;
}
