



 #include <stdio.h>
 #include <bits/stdc++.h>






using namespace std;





template<class T, size_t... I>
void print_tuple(ostream& s, T const& a, index_sequence<I...>){
  using swallow = int[];
  (void)swallow{0, (void(s << (I == 0? "" : ", ") << get<I>(a)), 0)...};
}

template<class T>
ostream& print_collection(ostream& s, T const& a);
template<class... A>
ostream& operator<<(ostream& s, tuple<A...> const& a);
template<class A, class B>
ostream& operator<<(ostream& s, pair<A, B> const& a);

template<class T, size_t I>
ostream& operator<<(ostream& s, array<T, I> const& a) { return print_collection(s, a); }
template<class T>
ostream& operator<<(ostream& s, vector<T> const& a) { return print_collection(s, a); }
template<class T, class U>
ostream& operator<<(ostream& s, multimap<T, U> const& a) { return print_collection(s, a); }
template<class T>
ostream& operator<<(ostream& s, multiset<T> const& a) { return print_collection(s, a); }
template<class T, class U>
ostream& operator<<(ostream& s, map<T, U> const& a) { return print_collection(s, a); }
template<class T>
ostream& operator<<(ostream& s, set<T> const& a) { return print_collection(s, a); }

template<class T>
ostream& print_collection(ostream& s, T const& a){
  s << '[';
  for(auto it = begin(a); it != end(a); ++it){
    s << *it;
    if(it != prev(end(a))) s << " ";
  }
  return s << ']';
}

template<class... A>
ostream& operator<<(ostream& s, tuple<A...> const& a){
  s << '(';
  print_tuple(s, a, index_sequence_for<A...>{});
  return s << ')';
}

template<class A, class B>
ostream& operator<<(ostream& s, pair<A, B> const& a){
  return s << "(" << get<0>(a) << ", " << get<1>(a) << ")";
}








using li = long long int;
using lu = long long unsigned;
using ld = long double;


using pii = tuple<li, li>;
using piii = tuple<li, li, li>;
using piiii = tuple<li, li, li, li>;
using vi = vector<li>;
using vii = vector<pii>;
using viii = vector<piii>;
using vvi = vector<vi>;
using vvii = vector<vii>;
using vviii = vector<viii>;

template<class T>
using min_queue = priority_queue<T, vector<T>, greater<T> >;
template<class T>
using max_queue = priority_queue<T>;

struct empty_t {};



int ilog2(int x){ return 31 - __builtin_clz(x); }

template <class T>
struct identity : std::unary_function <T, T> {
  T operator() (const T& x) const {return x;}
};

template<class T>
T& smin(T& x, T const& y) { x = min(x,y); return x; }

template <class T>
T& smax(T& x, T const& y) { x = max(x, y); return x; }


template<typename T>
T isqrt(T const&x){
  static_assert(is_integral<T>::value, "is_integral<T>::value");
  assert(x>=T(0));
  T ret = static_cast<T>(sqrtl(x));
  while(ret>0 && ret*ret>x) --ret;
  while(x-ret*ret>2*ret) ++ret;
  return ret;
}

template<typename T>
T icbrt(T const&x) {
  static_assert(is_integral<T>::value, "is_integral<T>::value");
  assert(x>=T(0));
  T ret = static_cast<T>(cbrt(x));
  while(ret>0 && ret*ret*ret>x) --ret;
  while(x-ret*ret*ret>3*ret*(ret+1)) ++ret;
  return ret;
}



template<li M = 998244353>
struct Zn {
  static_assert(M > 2, "M > 2");
  static_assert(M < (1ll<<31), "M < (1ll<<31)");
  int value;

  Zn() : value(0) { }

  Zn(int x) : value(x%M) {
    if(value < 0) value += M;
  }

  Zn(li x) : value(x%M) {
    if(value < 0) value += M;
  }

  Zn& operator+=(Zn const& o) {
    value += o.value;
    if(value >= M) value -= M;
    return *this;
  }

  Zn& operator-=(Zn const& o) {
    value += M - o.value;
    if(value >= M) value -= M;
    return *this;
  }

  Zn& operator*=(Zn const& o) {
    value = ((li)value*(li)o.value)%M;
    return *this;
  }

  Zn& operator/=(Zn const& o) {
    return operator*=(o.inverse());
  }

  Zn operator-() const { Zn r; r.value = value ? M-value : 0; }
  Zn operator+(Zn const& o) const { Zn r; r.value = value+o.value; if(r.value>=M) r.value -= M; return r; }
  Zn operator-(Zn const& o) const { Zn r; r.value = value+M-o.value; if(r.value>=M) r.value -= M; return r; }
  Zn operator*(Zn const& o) const { return Zn((li)value * (li)o.value); }
  Zn operator/(Zn const& o) const { Zn a = *this; a /= o; return a; }

  Zn inverse() const {
    int a = value, b = M, u = 0, v = 1;
    while (a != 0) {
      int t = b / a;
      b -= t * a; swap(a, b);
      u -= t * v; swap(u, v);
    }
    return Zn(u);
  }

  bool operator==(Zn const& o) const { return value == o.value; }
  bool operator!=(Zn const& o) const { return value != o.value; }
  bool operator<(Zn const& o) const { return value < o.value; }
  bool operator>(Zn const& o) const { return value > o.value; }
  bool operator<=(Zn const& o) const { return value <= o.value; }
  bool operator>=(Zn const& o) const { return value >= o.value; }
};

template<li M>
Zn<M> pow(Zn<M> a, li b) {
  Zn<M> r = 1;
  while(b){
    if(b&1) r = r*a;
    a = a * a;
    b /= 2;
  }
  return r;
}

template<li M>
Zn<M> operator+(int const& x, Zn<M> const& o) { return Zn<M>(x) + o; }
template<li M>
Zn<M> operator+(li const& x, Zn<M> const& o) { return Zn<M>(x) + o; }

template<li M>
Zn<M> operator*(int const& x, Zn<M> const& o) { return Zn<M>(x) * o; }
template<li M>
Zn<M> operator*(li const& x, Zn<M> const& o) { return Zn<M>(x) * o; }

template<li M>
Zn<M> operator/(int const& x, Zn<M> const& o) { return Zn<M>(x) / o; }
template<li M>
Zn<M> operator/(li const& x, Zn<M> const& o) { return Zn<M>(x) / o; }


template<li M>
ostream& operator<<(ostream& ss, Zn<M> const& a) {
  return ss << a.value;
}

template<li M>
istream& operator>>(istream& ss, Zn<M> &a) {
  li x; ss>>x;
  a = Zn<M>(x);
  return ss;
}




template<li M = 998244353>
struct factorials {
  vector<Zn<M>> F, IF;

  factorials() {
    F.emplace_back(1); IF.emplace_back(1);
  }

  factorials(int n) {
    F.emplace_back(1); IF.emplace_back(1);
    reserve(n);
  }

  void reserve(int n) {
    if((int)F.size() > n) return;
    smax<int>(n, 2*F.size());
    int a = F.size();
    F.resize(n+1);
    for(li i = (a); i <= (li)(n); ++i) F[i] = i * F[i-1];
    IF.resize(n+1);
    IF[n] = 1/F[n];
    for(li i = (n-1); i >= (li)(a); --i) IF[i] = IF[i+1] * (i+1);
  }

  Zn<M> operator[](int n) {
    reserve(n+1);
    return F[n];
  }

  Zn<M> I(int n) {
    reserve(n+1);
    return IF[n];
  }
};

template<li M = 998244353>
static factorials<M> Factorials;

template<li M = 998244353>
Zn<M> Fact(int n) { return Factorials<M>[n]; }

template<li M = 998244353>
Zn<M> IFact(int n) { return Factorials<M>.I(n); }

template<li M = 998244353>
Zn<M> SmallInv(int n) {
  assert(n>=1);
  return IFact(n)*Fact(n-1);
}

template<li M = 998244353>
Zn<M> cnk(int n, int k) {
  if(k < 0 || k > n) return 0;
  return Fact(n) * IFact(k) * IFact(n-k);
}

template<li M = 998244353>
struct BinomialRow {
  Zn<M> N;
  vector<Zn<M>> A;

  BinomialRow(Zn<M> N_) {
    N = N_;
    A.emplace_back(1);
  }

  void reserve(int k) {
    if(k < (int)A.size()) return;
    int i = A.size()-1;
    A.resize(k+1);
    for(; i <= k; ++i) {
      A[i+1] = A[i] * (N - i) * SmallInv(i+1);
    }
  }

  Zn<M> operator[](int k) {
    if(k >= (int)A.size()) reserve(k);
    return A[k];
  }
};

using ZN = Zn<>;

ZN dp[3001][3001];
ZN ans[3001];

int main(){
  ios::sync_with_stdio(0); cin.tie(0);
  li n,c; cin>>n>>c;
  vi A(n);
  for(li i = 0; i < (li)(n); ++i) {
    cin>>A[i];
    A[i]-=1;
  }

  vector<ZN> P2(5000), IP2(5000);
  P2[0] = 1;
  for(li i = 0; i < (li)(4999); ++i) P2[i+1] = P2[i]*ZN(2);
  for(li i = 0; i < (li)(5000); ++i) IP2[i] = ZN(1)/P2[i];

  if(c == 1) {
    for(li i = 0; i < (li)(n+1); ++i) {
      cout << (i == 0 ? 0 : cnk(n,i)) << ' ';
    }
    cout << endl;
    return 0;
  }

  dp[0][0] = 1;
  ans[0] = P2[n]-1;

  for(li i = 0; i < (li)(n); ++i) {
    vi cnt(c, 0);
    li call = 0;
    ZN p = 1;
    for(li j = (i+1); j <= (li)(n-1); ++j) if(A[j] != A[i]) {
      if(!cnt[A[j]]) {
        call++;
        cnt[A[j]]++;
        if(call == c-1) {
          for(li k = 0; k < (li)(c); ++k) if(k != A[i]) p *= (P2[cnt[k]]-ZN(1));
          for(li k = 0; k < (li)(n); ++k) dp[j+1][k+1] += dp[i][k] * p;
          for(li k = 0; k < (li)(n); ++k) ans[k+1] += dp[i][k] * p * P2[n-1-j];
        }
      }else{
        if(call == c-1) {
          for(li k = 0; k < (li)(n); ++k) dp[j+1][k+1] += dp[i][k] * p * P2[cnt[A[j]]];
          for(li k = 0; k < (li)(n); ++k) ans[k+1] += dp[i][k] * p * P2[cnt[A[j]]] * P2[n-1-j];
          p /= (P2[cnt[A[j]]]-ZN(1));
        }
        cnt[A[j]]++;
        if(call == c-1) p *= (P2[cnt[A[j]]]-ZN(1));
      }
    }
    for(li k = 0; k < (li)(n+1); ++k) dp[i+1][k] += dp[i][k];
  }

  for(li k = (n-1); k >= (li)(0); --k) ans[k] -= ans[k+1];
  for(li k = 0; k < (li)(n+1); ++k) cout << ans[k] << ' ';
  cout << endl;
  return 0;
}
