#include <iostream>
#include <vector>
#include <cmath>
#include <algorithm>
#include <chrono>
#include <random>
#include <iomanip>

using namespace std;

// Cấu trúc lưu hộ gia đình
struct Item {
    double a;
    int id;
};

// Hàm xoá nhanh 1 phần tử khỏi vector (O(V))
void remove_from_group(vector<int>& vec, int val) {
    for (int i = 0; i < (int)vec.size(); ++i) {
        if (vec[i] == val) {
            vec[i] = vec.back();
            vec.pop_back();
            return;
        }
    }
}

int main() {
    // Tối ưu I/O
    ios_base::sync_with_stdio(false);
    cin.tie(NULL);

    int N;
    double L;
    if (!(cin >> N >> L)) return 0;

    vector<Item> items(N + 1);
    vector<double> a(N + 1);
    for (int i = 1; i <= N; ++i) {
        cin >> items[i].a;
        items[i].id = i;
        a[i] = items[i].a;
    }

    // BƯỚC 1: SẮP XẾP VÀ QUY HOẠCH ĐỘNG (DP) ĐỂ TÌM BASELINE TỐT
    sort(items.begin() + 1, items.end(), [](const Item& x, const Item& y) {
        return x.a < y.a;
    });

    vector<double> dp(N + 1, 1e18);
    vector<int> trace(N + 1, 0);
    dp[0] = 0.0;

    for (int i = 1; i <= N; ++i) {
        for (int j = 0; j < i; ++j) {
            double S = 0;
            for (int m = j + 1; m <= i; ++m) S += items[m].a;
            
            double H = S / L;
            double cost = 0;
            for (int m = j + 1; m <= i; ++m) {
                cost += abs(H - items[m].a / H);
            }
            
            if (dp[j] + cost < dp[i]) {
                dp[i] = dp[j] + cost;
                trace[i] = j;
            }
        }
    }

    // Truy vết DP để lấy phân hoạch ban đầu
    vector<int> initial_group(N + 1);
    int curr = N;
    int g_id = 0;
    while (curr > 0) {
        int prev = trace[curr];
        for (int i = prev + 1; i <= curr; ++i) {
            initial_group[items[i].id] = g_id; // Đưa về index ban đầu của hộ
        }
        g_id++;
        curr = prev;
    }

    // BƯỚC 2: SIMULATED ANNEALING (SA)
    vector<int> group_of = initial_group;
    vector<vector<int>> members(N); // Tối đa N dải đất
    vector<double> sum_group(N, 0.0);
    vector<double> group_cost(N, 0.0);

    for (int i = 1; i <= N; ++i) {
        members[group_of[i]].push_back(i);
        sum_group[group_of[i]] += a[i];
    }

    auto recalc_group = [&](int g) {
        if (members[g].empty()) {
            sum_group[g] = 0;
            group_cost[g] = 0;
            return;
        }
        double S = 0;
        for (int u : members[g]) S += a[u];
        sum_group[g] = S;
        double H = S / L;
        double c = 0;
        for (int u : members[g]) c += abs(H - a[u] / H);
        group_cost[g] = c;
    };

    double current_total_cost = 0;
    for (int g = 0; g < N; ++g) {
        recalc_group(g);
        current_total_cost += group_cost[g];
    }

    double best_cost = current_total_cost;
    vector<int> best_group_of = group_of;

    mt19937 rng(1337); // Seed cố định để dễ debug
    auto get_time = []() {
        return (double)clock() / CLOCKS_PER_SEC;
    };

    double start_time = get_time();
    double TIME_LIMIT = 4.8; // Chạy 4.8s để an toàn trong giới hạn 5s
    double T_start = 100.0;
    double T_end = 1e-6;

    while (true) {
        double elapsed = get_time() - start_time;
        if (elapsed > TIME_LIMIT) break;

        // Tính nhiệt độ hiện tại (giảm dần)
        double progress = elapsed / TIME_LIMIT;
        double current_T = T_start * pow(T_end / T_start, progress);

        int type = rng() % 2; // 0: Move, 1: Swap

        if (type == 0) {
            // MOVE: Chuyển 1 phần tử sang nhóm khác
            int u = uniform_int_distribution<int>(1, N)(rng);
            int g_old = group_of[u];
            int g_new = uniform_int_distribution<int>(0, N - 1)(rng);
            
            if (g_old == g_new) continue;

            // Đánh giá nhanh O(|V|)
            double cost_old_new = 0;
            if (members[g_old].size() > 1) {
                double H_old = (sum_group[g_old] - a[u]) / L;
                for (int x : members[g_old]) {
                    if (x != u) cost_old_new += abs(H_old - a[x] / H_old);
                }
            }

            double H_new = (sum_group[g_new] + a[u]) / L;
            double cost_new_new = abs(H_new - a[u] / H_new);
            for (int x : members[g_new]) {
                cost_new_new += abs(H_new - a[x] / H_new);
            }

            double delta = (cost_old_new + cost_new_new) - (group_cost[g_old] + group_cost[g_new]);

            // Xác suất chấp nhận
            if (delta < 0 || exp(-delta / current_T) > uniform_real_distribution<double>(0.0, 1.0)(rng)) {
                group_of[u] = g_new;
                remove_from_group(members[g_old], u);
                members[g_new].push_back(u);
                recalc_group(g_old);
                recalc_group(g_new);
                current_total_cost += delta;

                if (current_total_cost < best_cost) {
                    best_cost = current_total_cost;
                    best_group_of = group_of;
                }
            }
        } else {
            // SWAP: Đổi chỗ 2 phần tử ở 2 nhóm khác nhau
            int u = uniform_int_distribution<int>(1, N)(rng);
            int v = uniform_int_distribution<int>(1, N)(rng);
            int g_old = group_of[u];
            int g_new = group_of[v];
            
            if (g_old == g_new) continue;

            double H_old = (sum_group[g_old] - a[u] + a[v]) / L;
            double cost_old_new = abs(H_old - a[v] / H_old);
            for (int x : members[g_old]) {
                if (x != u) cost_old_new += abs(H_old - a[x] / H_old);
            }

            double H_new = (sum_group[g_new] - a[v] + a[u]) / L;
            double cost_new_new = abs(H_new - a[u] / H_new);
            for (int x : members[g_new]) {
                if (x != v) cost_new_new += abs(H_new - a[x] / H_new);
            }

            double delta = (cost_old_new + cost_new_new) - (group_cost[g_old] + group_cost[g_new]);

            if (delta < 0 || exp(-delta / current_T) > uniform_real_distribution<double>(0.0, 1.0)(rng)) {
                group_of[u] = g_new;
                group_of[v] = g_old;
                remove_from_group(members[g_old], u);
                remove_from_group(members[g_new], v);
                members[g_old].push_back(v);
                members[g_new].push_back(u);
                recalc_group(g_old);
                recalc_group(g_new);
                current_total_cost += delta;

                if (current_total_cost < best_cost) {
                    best_cost = current_total_cost;
                    best_group_of = group_of;
                }
            }
        }
    }

    // Đưa ra output
    vector<vector<int>> final_groups(N);
    for (int i = 1; i <= N; ++i) {
        final_groups[best_group_of[i]].push_back(i);
    }
    
    int k_used = 0;
    for (int i = 0; i < N; ++i) {
        if (!final_groups[i].empty()) k_used++;
    }

    // In chi phí nhỏ nhất (có thể làm tròn tới 6 chữ số thập phân)
    cout << fixed << setprecision(6) << best_cost << "\n";
    
    // In ra cách chia: số nhóm k, sau đó mỗi nhóm in ra số hộ và id của các hộ
    cout << k_used << "\n";
    for (int i = 0; i < N; ++i) {
        if (!final_groups[i].empty()) {
            cout << final_groups[i].size();
            for (int x : final_groups[i]) cout << " " << x;
            cout << "\n";
        }
    }

    return 0;
}