#include <bits/stdc++.h>
using namespace std;
using i64 = long long;
#define rep(i,s,e) for(i64 (i) = (s);(i) < (e);(i)++)
#define all(x) x.begin(),x.end()
#define let auto const

template<typename... Types>
struct dynarr: std::vector<Types...> {
  using std::vector<Types...>::vector;
  using size_type = typename std::vector<Types...>::size_type;
  auto&& operator[](size_type i) { return this->at(i); }
  auto&& operator[](size_type i) const { return this->at(i); }
};

static vector<i64> mm(3030, -1);
i64& memo(i64 r) {
  return mm[r];
}

struct modint {
  i64 a;
  static i64& M() {
    static i64 mod_ = 2999;
    return mod_;
  }
  modint(const i64 x = 0) noexcept: a((x % M() + M()) % M()) {}
  i64 value() const noexcept { return a; }
  modint& operator=(const int r) {
    a = (r % M() + M()) % M();
    return *this;
  }
  modint& operator+=(const modint r) noexcept {
    a += r.a;
    if(a >= M()) a -= M();
    return *this;
  }
  modint& operator-=(const modint r) noexcept {
    a -= r.a;
    if(a < 0) a += M();
    return *this;
  }
  modint& operator*=(const modint r) noexcept {
    a = a * r.a % M();
    return *this;
  }
  modint& operator/=(modint r) noexcept {
    if(memo(r.value()) != -1) {
      return *this *= modint(memo(r.value()));
    }
    i64 rr = r.value();
    i64 ex = M() - 2;
    modint inv(1);
    while(ex) {
      if(ex & 1) {
        inv *= r;
      }
      r *= r;
      ex >>= 1;
    }
    memo(rr) = inv.value();
    return *this *= inv;
  }

  modint operator+(const modint r) const {
    return modint(*this) += r;
  }
  modint operator-(const modint r) const {
    return modint(*this) -= r;
  }
  modint operator*(const modint r) const {
    return modint(*this) *= r;
  }
  modint operator/(const modint r) const {
    return modint(*this) /= r;
  }
};



#include <vector>
#include <array>
#include <complex>
#include <cassert>
#include <set>
#include <iostream>
using i64 = long long;

template<class T>
std::vector<T> newton_interpolation(std::vector<std::pair<T, T>> ps) {
  std::vector<T> diff(ps.size());
  diff[0] = ps[0].second;
  std::vector<T> x(ps.size()), y(ps.size());
  for(int i = 0;i < ps.size(); i++) {
    x[i] = ps[i].first, y[i] = ps[i].second;
  }
  for(int i = 1;i < ps.size();i++) {
    std::vector<T> d(ps.size() - i);
    for(int j = 0;j + i < ps.size(); j++) {
      d[j] = (y[j + 1] - y[j]) / (x[j + i] - x[j]);
    }
    diff[i] = d[0];
    swap(y, d);
  }

  std::vector<T> ans(ps.size());

  std::vector<T> c(ps.size() + 1);
  c[0] = 1;


  for(int i = 0;i < ps.size();i++) {
    for(int j = 0;j < ps.size();j++) {
      ans[j] += diff[i] * c[j];
    }
    if(i + 1 == ps.size()) break;

    std::vector<T> next(ps.size() + 1);
    for(int j = 0;j < ps.size();j++) {
      next[j + 1] = c[j];
    }
    for(int j = 0;j < ps.size();j++) {
      next[j] -= c[j] * ps[i].first;
    }
    swap(c, next);
  }
  return ans;
}

int main() {
  i64 p;
  cin >> p;
  modint::M() = p;
  dynarr<i64> a(p);
  rep(i,0,p) cin >> a[i];
  vector<pair<modint, modint>> vec;
  rep(i,0,p) {
    vec.push_back({modint(i), modint(a[i])});
  }
  auto pp = newton_interpolation(vec);
  rep(i,0,p) {
    cout << pp[i].value() << " \n"[i + 1 == p];
  }
}


Measured memory_bytes: 640