#include using namespace std; #define TRACE(x) cerr << __LINE__ << ": " << #x << " = " << x << endl #define _ << " _ " << template struct is_container : false_type {}; template struct is_container> : true_type {}; template struct is_container> : true_type {}; template struct is_container> : true_type {}; template struct is_container> : true_type {}; template struct is_container> : true_type {}; template struct is_container> : true_type {}; template struct is_container> : true_type {}; template::value>::type> ostream& operator<<(ostream &o, T x) { int f = 1; o << "{"; for (auto y : x) { o << (f ? "" : ", ") << y; f = 0; } return o << "}"; } template ostream& operator<<(ostream &o, pair x) { return o << "(" << x.first << ", " << x.second << ")"; } #define fi first #define se second typedef long long ll; typedef long double ld; typedef pair pii; typedef pair pll; typedef vector vi; typedef vector vll; // source: https://gist.github.com/Chillee/4982ba0840745f63f3771bd84f280557#file-ntt-cpp template struct NTT { constexpr static int lg2(int n) { return 32 - __builtin_clz(n - 1); } const static int MAXN = 1 << lg2(maxn), MOD = 167772161, root = 3; int rev[MAXN], rt[MAXN]; int mul(int a, int b) { return (long long)a * b % MOD; } int sub(int a, int b) { return b > a ? a - b + MOD : a - b; } int add(int a, int b) { return a + b >= MOD ? a + b - MOD : a + b; } int binExp(int base, long long exp) { if (exp == 0) return 1; return mul(binExp(mul(base, base), exp / 2), exp & 1 ? base : 1); } NTT() { rt[1] = 1; for (int k = 1; k < lg2(MAXN); k++) { int z[] = {1, binExp(root, (MOD - 1) >> (k + 1))}; for (int i = (1 << k); i < 2 << k; i++) rt[i] = mul(rt[i / 2], z[i & 1]); } } void ntt(int *a, int n) { for (int i = 0; i < n; i++) rev[i] = (rev[i / 2] | (i & 1) << lg2(n)) / 2; for (int i = 0; i < n; i++) if (i < rev[i]) swap(a[i], a[rev[i]]); for (int k = 1; k < n; k *= 2) for (int i = 0; i < n; i += 2 * k) for (int j = 0; j < k; j++) { int z = mul(rt[j + k], a[i + j + k]); a[i + j + k] = sub(a[i + j], z); a[i + j] = add(a[i + j], z); } } int in[2][MAXN]; vector multiply(const vector &a, const vector &b) { //fill(all(in[0]), 0), fill(all(in[1]), 0); fill(in[0], in[0] + MAXN, 0), fill(in[1], in[1] + MAXN, 0); if (a.empty() || b.empty()) return {}; int sz = a.size() + b.size() - 1, n = 1 << lg2(sz); //copy(all(a), in[0]), copy(all(b), in[1]); copy(a.begin(), a.end(), in[0]), copy(b.begin(), b.end(), in[1]); ntt(in[0], n), ntt(in[1], n); int invN = binExp(n, MOD - 2); for (int i = 0; i < n; i++) in[0][i] = mul(mul(in[0][i], in[1][i]), invN); reverse(in[0] + 1, in[0] + n); ntt(in[0], n); return vector(in[0], in[0] + sz); } }; const int MAX = 405; NTT ntt; int dp1[MAX][MAX][MAX], dp2[MAX][MAX][MAX]; int main() { ios_base::sync_with_stdio(false); cin.tie(0); int n, k; cin >> n >> k; vi W(n); for (int i = 0; i < n; i++) cin >> W[i]; dp1[0][0][0] = 1; for (int i = 0; i < n; i++) for (int c = 0; c < MAX; c++) for (int w = 0; w < MAX; w++) { dp1[i+1][c][w] = dp1[i][c][w]; if (W[i] <= w && 1 <= c) dp1[i+1][c][w] = ntt.add(dp1[i+1][c][w], dp1[i][c-1][w-W[i]]); } dp2[n][0][0] = 1; for (int i = n - 1; i >= 0; i--) for (int c = 0; c < MAX; c++) for (int w = 0; w < MAX; w++) { dp2[i][c][w] = dp2[i+1][c][w]; if (W[i] <= w && 1 <= c) dp2[i][c][w] = ntt.add(dp2[i][c][w], dp2[i+1][c-1][w-W[i]]); } vi a(MAX*MAX*2), b(MAX*MAX*2); for (int i = 0; i < n; i++) { fill(a.begin(), a.end(), 0); fill(b.begin(), b.end(), 0); for (int c = 0; c < MAX; c++) for (int w = 0; w < MAX; w++) { a[MAX*2*c + w] = dp1[i][c][w]; b[MAX*2*c + w] = dp2[i+1][c][w]; } auto m = ntt.multiply(a, b); vi sol(n - 1); for (int c = 1; c < n; c++) for (int w = k - W[i] + 1; w <= k; w++) sol[c - 1] = ntt.add(sol[c - 1], m[MAX*2*c + w]); for (int x : sol) cout << x << ' '; cout << '\n'; } return 0; }