#include <iostream>
#include <string>
#include <vector>
#include <iterator>  // std::back_inserter()
#include <algorithm>  // std::copy()
#include <functional>  // std::greater<T>()
#include <utility>  // std::swap()
#include <numeric>  // accumulate(ALL(vec), 0)  0 は初期値
#include <cmath>
#include <climits>  // INT_MIN
#include <ios>     // std::left, std::right
#include <iomanip> // std::setw(int), std::setfill(char)

using namespace std;

// macro
#define ALL(obj) (obj).begin(), (obj).end()
#define REP(i, n) for (int i=0; i < (int)(n); i++)  // 0 ~ n-1
#define REPN(i, n) for (int i=1; i <= (int)(n); i++)  // 1 ~ n
#define DESCEND greater<int>()  // sort 降順 大きい順
#define UNIQUE(vec) (vec).erase(unique(ALL((vec))), (vec).end());  // 必ずsortを行なってから
#define MIN(vec) min_element(ALL((vec)))  // 値を取り出すときは * を先頭につける
#define MAX(vec) max_element(ALL((vec)))
#define IDX(vec, element_iter) distance((vec).begin(), element_iter)
#define SUM(vec) accumulate(ALL((vec)), 0)  // 0 は初期値
#define COPY(vec1, vec2) copy(ALL(vec1), back_inserter(vec2))  // vec1をvec2にコピーする
#define zero_pad(num) setfill('0') << std::right << setw(num)  // 直後の要素をパディング
#define space_pad(num) setfill(' ') << std::right << setw(num)  // 直後の要素をパディング

// func declaration
template <class T> void printVec(vector<T>&);
template <class T> void print2DVec(vector< vector<T> >&);
template <class T> void calcVec(vector<T>&, int, char);
bool checkMultiple(vector<int>&, int);
int ctoi(const char);  // char to int

// const
const int INF = 10000000;

/*MEMO
・辞書順
abc < abcd, atcoder < atlas
・イテレータ
std::vector<int>::iterator とタイプするのは面倒なので、
 通常は型推論の auto を使用する。
 auto iter = max_element(ALL(vec));
・2次元配列
vector<vector<int>> vec = {{1, 2, 3}, {4, 5, 6}}
・20×10の配列
vector<vector<int>> vec(20, vector<int>(10, 0));
・(n, m)の多次元配列
vector< vector<int> > vec(n, vector<int>(m, 0))  // 0で初期化
*/

/*
void InsertionSort(vector<int> &vec) {
    *
     * 挿入ソート(トランプの並べ替え)
     * 未ソート部分の一番左端からスタート
     * 挿入できるインデックスを取得して間に挿入
     *
    for (int i = 1; i < vec.size(); ++i) {
        int left = vec.at(i);  // 未ソートの左端

        // ソート済みと比較していく
        int j = i - 1;  // ソート済みの右端のインデックス

        // 条件は左から順に読み取られることに注意
        while (j >= 0 && vec.at(j) > left) {
            vec.at(j + 1) = vec.at(j);
            j--;
        }
        int insert_idx = j + 1;  // 最後引かれた分を１足してる
        vec.at(insert_idx) = left;
        // printVec(vec);
    }
}
*/

// global
int cnt = 0;

void InsertionSort(vector<int> &vec, int g = 1) {
    /*
     * 挿入ソート(トランプの並べ替え)
     * 未ソート部分の一番左端からスタート
     * 挿入できるインデックスを取得して間に挿入
     */
    for (int i = g; i < vec.size(); ++i) {
        int left = vec.at(i);  // 未ソートの左端

        // ソート済みと比較していく
        // シェルソートの間隔はg
        int j = i - g;  // ソート済みの右端のインデックス
        // j = 0, g, 2g, 3g, ...

        // 条件は左から順に読み取られることに注意
        while (j >= 0 && vec.at(j) > left) {
            vec.at(j + g) = vec.at(j);
            j -= g;
            cnt++;
        }
        int insert_idx = j + g;  // 最後引かれた分をg足してる
        vec.at(insert_idx) = left;
        // printVec(vec);
    }

}

int ShellSort(vector<int> &vec) {
    vector<int> G;  // 長さ m のベクトル
    // Gを決める
    int i = 1;
    do  {
        G.push_back(i);
        i = 3*i + 1;
    } while (i < vec.size());

    // output
    int m = G.size();
    cout << m << endl;
    reverse(ALL(G));
    printVec(G);

    REP(i, m) {
        InsertionSort(vec, G.at(i));
    }
    return cnt;
}


int main() {
    /*
     * Shell Sort
     * g離れた要素のみをソートする
     */
    // input
    int N;
    cin >> N;
    vector<int> vec(N);
    REP(i, N) cin >> vec.at(i);
    
    // calculation
    ShellSort(vec);
    cout << ::cnt << endl;
    REP(i, N) {
        cout << vec.at(i) << endl;
    }
    return 0;
}


// function
template <class T> void printVec(vector<T>& vec) {
    // 1要素ずつ、空白・改行なしで出力
    REP(i, vec.size()) {
        if (i) cout << " ";
        cout << vec.at(i);
    }
    cout << endl;
}



Measured memory_bytes: 6784