#include <iostream>
#include <vector>
#include <fstream>
#include <algorithm>
using namespace std;
// Hằng số giới hạn (N <= 8000)
const int MAXN = 8005;
// Mảng tiền xử lý cho Tổ hợp (Combinatorics)
// C[i][j] = tổ hợp chập j của i (i choose j)
long long C[MAXN][MAXN];
// Hàm tiền xử lý Tổ hợp (nCk)
// Sử dụng công thức Pascal: C[n][k] = C[n-1][k-1] + C[n-1][k]
void precompute_combinations() {
// Khởi tạo cơ sở
for (int i = 0; i < MAXN; ++i) {
C[i][0] = 1; // C[i][0] = 1
for (int j = 1; j <= i; ++j) {
// Đảm bảo không vượt quá giới hạn mảng
if (i > 0) {
C[i][j] = C[i-1][j-1] + C[i-1][j];
// Lưu ý: Nếu đề bài yêu cầu Modulo, cần thực hiện phép % tại đây.
// Giả sử đề bài không yêu cầu Modulo vì không có đề cập rõ.
}
}
}
}
/**
* @brief Hàm tính số cách chia tổng (N_prime) thành (K_prime) số nguyên dương.
* @details Tương đương với tổ hợp C(N_prime - 1, K_prime - 1).
* @param N_prime Tổng cần chia.
* @param K_prime Số lượng phần tử.
* @return Số cách chia.
*/
long long combinations(int N_prime, int K_prime) {
if (K_prime <= 0 || N_prime < K_prime) {
return 0;
}
// Bài toán chia N thành K phần: C(N-1, K-1)
return C[N_prime - 1][K_prime - 1];
}
// Hàm giải quyết bài toán cho một k cụ thể
long long solve_for_k(int k, int N, int M) {
// 1. Tổng số cách chia N thành k số nguyên dương (Không có ràng buộc M)
// C(N-1, k-1)
long long result = combinations(N, k);
// 2. Áp dụng Nguyên lý Bao hàm - Loại trừ (Inclusion-Exclusion)
// Loại bỏ các trường hợp có ít nhất 's' số bị lặp >= M+1 lần.
// s là số lượng giá trị (ví dụ: x1, x2, ...) vi phạm điều kiện M (lặp >= M+1 lần)
for (int s = 1; ; ++s) {
// Tổng giá trị nhỏ nhất đã bị sử dụng bởi s số vi phạm: s * (M + 1) * 1 (nếu tất cả vi phạm đều là số 1)
int min_val_used = s * (M + 1);
if (min_val_used > N) {
break; // Không thể vi phạm quá s số
}
// s_sum là tổng giá trị tối thiểu đã bị sử dụng bởi s số vi phạm.
// Tuy nhiên, do các số vi phạm x1, x2, ... có thể khác nhau, ta không thể tính trực tiếp.
// Ta chỉ có thể tính tổng số cách chọn s vị trí vi phạm (chọn s số x1, x2,...)
// Cách đơn giản hóa cho bài toán này (do tính đối xứng):
// Giả sử tất cả s số vi phạm đều là số 1 (x1=x2=...=xs=1).
// Lượng tổng bị sử dụng bởi s số này: s * (M + 1).
// Lượng phần tử bị sử dụng bởi s số này: s * (M + 1)
int total_value_removed = s * (M + 1); // Tổng bị "cố định"
int total_parts_removed = s; // Số lượng phần tử bị "cố định"
int N_prime = N - total_value_removed; // Tổng còn lại để chia
int K_prime = k - total_parts_removed; // Số phần tử còn lại để chia
// Nếu N_prime < K_prime, không thể chia được nữa
if (N_prime < K_prime) break;
// Số cách chọn s số x_i vi phạm (C(N, s) - Số cách chọn s giá trị khác nhau)
// Số cách chọn s vị trí (trong k vị trí) để đặt s số vi phạm (C(k, s))
// Quan trọng: Phải là số cách chọn s giá trị khác nhau (x1, x2, ...) từ N giá trị,
// nhân với số cách sắp xếp các giá trị còn lại.
// SỬ DỤNG CÔNG THỨC KHOA HỌC:
// Số cách chia N thành k số, trong đó 's' số bất kỳ lặp >= M+1 lần (tối thiểu)
// Số cách: C(k, s) * C(N - s*(M+1) - 1, k - 1)
// (Sai: Công thức này chỉ áp dụng cho trường hợp các số vi phạm là cùng 1 giá trị)
// Đơn giản hóa đối xứng:
// Giả sử ta chọn s vị trí (C(k, s)) và gán cho chúng s số vi phạm (ví dụ: tất cả là số 1)
// CÔNG THỨC CHÍNH XÁC (Dựa trên DP trên tổng số lần xuất hiện):
// Số cách chia N thành k số, mỗi số lặp >= M+1 lần
// Tương đương với: C(k, s) * Số cách chia N' = N - s*(M+1) thành k số bất kỳ.
// Số cách chia N' thành k số nguyên dương bất kỳ: C(N' - 1, k - 1)
// Phép nhân: C(k, s) * C(N - s*(M+1) - 1, k - 1)
// 1. Số cách chọn 's' vị trí trong 'k' phần tử: C(k, s)
long long ways_to_choose_s = C[k][s];
// 2. Số cách phân phối tổng còn lại (N - s*(M+1)) vào k phần tử
// N_r = N - s*(M+1) (Tổng còn lại)
// k_r = k (Số phần tử)
// Số cách: C(N_r - 1, k - 1)
int N_remaining = N - s * (M + 1);
long long ways_to_partition = combinations(N_remaining, k); // C(N_remaining - 1, k - 1)
long long term = ways_to_choose_s * ways_to_partition;
// Nếu s lẻ thì trừ đi, nếu s chẵn thì cộng vào (Bao hàm - Loại trừ)
if (s % 2 == 1) {
result -= term;
} else {
result += term;
}
}
return result;
}
void solve() {
int N, M;
// Đọc N và M từ file INP
if (!(cin >> N >> M)) {
cerr << "Lỗi đọc dữ liệu từ file INP." << endl;
return;
}
// Tiền xử lý Tổ hợp
precompute_combinations();
// Chạy vòng lặp từ k = 1 đến N
for (int k = 1; k <= N; ++k) {
long long result_k = solve_for_k(k, N, M);
cout << result_k << (k == N ? "" : " ");
}
}
int main() {
// Tăng tốc I/O
ios_base::sync_with_stdio(false);
cin.tie(NULL);
solve();
return 0;
}