Problem:
Score : 600 points

Problem Statement

Given are a prime number p and a sequence of p integers a_0, \ldots, a_{p-1} consisting of zeros and ones.

Find a polynomial of degree at most p-1, f(x) = b_{p-1} x^{p-1} + b_{p-2} x^{p-2} + \ldots + b_0, satisfying the following conditions:

For each i (0 \leq i \leq p-1), b_i is an integer such that 0 \leq b_i \leq p-1.

For each i (0 \leq i \leq p-1), f(i) \equiv a_i \pmod p.

Constraints

2 \leq p \leq 2999

p is a prime number.

0 \leq a_i \leq 1

Input

Input is given from Standard Input in the following format:

p
a_0 a_1 \ldots a_{p-1}

Output

Print b_0, b_1, \ldots, b_{p-1} of a polynomial f(x) satisfying the conditions, in this order, with spaces in between.

It can be proved that a solution always exists. If multiple solutions exist, any of them will be accepted.

Sample Input 1

2
1 0

Sample Output 1

1 1

f(x) = x + 1 satisfies the conditions, as follows:

f(0) = 0 + 1 = 1 \equiv 1 \pmod 2

f(1) = 1 + 1 = 2 \equiv 0 \pmod 2

Sample Input 2

3
0 0 0

Sample Output 2

0 0 0

f(x) = 0 is also valid.

Sample Input 3

5
0 1 0 1 0

Sample Output 3

0 2 0 1 3

Solution in C++14 (GCC 5.4.1) (judge verdict: Accepted)

#include<iostream>
#include<cassert>
#include<stdexcept>
#include<utility>
#include<functional>
#include<numeric>
#include<cmath>
#include<algorithm>
#include<cstdio>
#include<cstdlib>
#include<array>
#include<stack>
#include<queue>
#include<deque>
#include<vector>
#include<complex>
#include<set>
#include<map>
#include<unordered_map>
#include<unordered_set>
#include<string>
#include<bitset>
using namespace std;
using ll=long long;

#include<vector>
#include<algorithm>
namespace ProconLib{

    namespace DetailNS{
        template<typename T>
        struct DefaultDetail{
            static bool isZero(T x){
                return x<=T(0);
            }
        };
    }
    template<typename T>
    class Polynomial{
        int N;
        std::vector<T> dat;
        
        public:
        Polynomial(int N):N(N),dat(N+1){}
        Polynomial():Polynomial(0){}
        Polynomial(const Polynomial& obj):N(obj.N),dat(obj.dat){}
        Polynomial(const Polynomial&& obj):N(obj.N),dat(std::move(obj.dat)){}

        int degree(){return N;}
        void resize(int N){ this->N=N; dat.resize(N+1,T(0));}
        template<typename Detail=DetailNS::DefaultDetail<T>>
        void shrink();
        T& operator[](int pos){return dat[pos];}
        const T& operator[](int pos) const {return dat[pos];}

        T operator()(T x);
    };

    template<typename T>
    Polynomial<T>& operator+=(Polynomial<T> &lhs,Polynomial<T> rhs);
    template<typename T>
    Polynomial<T>& operator-=(Polynomial<T> &lhs,Polynomial<T> rhs);
    template<typename T>
    Polynomial<T>& operator*=(Polynomial<T> &lhs,Polynomial<T> rhs);
    template<typename T>
    Polynomial<T> operator+(Polynomial<T> lhs,Polynomial<T> rhs){return lhs+=rhs;}
    template<typename T>
    Polynomial<T> operator-(Polynomial<T> lhs,Polynomial<T> rhs){return lhs-=rhs;}
    template<typename T>
    Polynomial<T> operator*(Polynomial<T> lhs,Polynomial<T> rhs){return lhs*=rhs;}

    template<typename T>
    template<typename Detail>
    void Polynomial<T>::shrink(){ 
        while(N){
            if(Detail::isZero(dat[N])) N--;
            else break;
        }
        resize(N);
    }

    template<typename T>
    Polynomial<T>& operator+=(Polynomial<T> &lhs,Polynomial<T> rhs){
        lhs.resize(std::max(lhs.degree(),rhs.degree()));
        for(int i=0;i<=rhs.degree();i++) lhs[i]+=rhs[i];
        return lhs;
    }

    template<typename T>
    Polynomial<T>& operator-=(Polynomial<T> &lhs,Polynomial<T> rhs){
        lhs.resize(std::max(lhs.degree(),rhs.degree()));
        for(int i=0;i<=rhs.degree();i++) lhs[i]-=rhs[i];
        return lhs;
    }


    template<typename T>
    Polynomial<T>& operator*=(Polynomial<T> &lhs,Polynomial<T> rhs){
        Polynomial<T> lhsTmp=lhs;
        lhs.resize(lhs.degree()+rhs.degree());
        for(int i=0;i<=lhsTmp.degree();i++) lhs[i]=T(0);
        for(int i=0;i<=lhsTmp.degree();i++){
            for(int j=0;j<=rhs.degree();j++){
                lhs[i+j]+=lhsTmp[i]*rhs[j];
            }
        }
        return lhs;
    }

    template<typename T>
    Polynomial<T> operator+(Polynomial<T> poly){
        auto res=poly;
        return res;
    }

    template<typename T>
    Polynomial<T> operator-(Polynomial<T> poly){
        auto res=poly;
        for(int i=0;i<=poly.degree();i++) res[i]=-res[i];
        return res;
    }

    template<typename T>
    T Polynomial<T>::operator()(T x){
        T res=T(0);
        T px=T(1);
        for(int i=0;i<=degree();i++){
            res+=dat[i]*px;
            px*=x;
        }
        return res;
    }


}
using namespace ProconLib;

int powm(int x,int k,int p){
    int res=1;
    while(k){
        if(k&1) res=res*x%p;
        k>>=1;
        x=x*x%p;
    }
    return res;
}
int inv(int x,int p){
    return powm(x,p-2,p);
}
using P=Polynomial<int>;
int main(){
    int p;
    cin>>p;
    vector<int> a(p);
    for(int i=0;i<p;i++) cin>>a[i];

    vector<vector<P>> dp(2,vector<P>(p+1));
    dp[0][0][0]=1;
    for(int i=0;i<p;i++){
        if(a[i]){
            int r=1;
            for(int j=0;j<p;j++){
                if(i!=j) r=r*inv(i-j,p)%p;
            }
            dp[1][i+1]+=dp[0][i];
            for(int j=0;j<=dp[1][i+1].degree();j++) dp[1][i+1][j]*=r;
        }
        P poly(2);
        poly[0]=-i;
        poly[1]=1;
        dp[0][i+1]+=dp[0][i]*poly;
        dp[1][i+1]+=dp[1][i]*poly;
        for(int j=0;j<=dp[0][i+1].degree();j++) dp[0][i+1][j]%=p;
        for(int j=0;j<=dp[1][i+1].degree();j++) dp[1][i+1][j]%=p;
}
    for(int i=0;i+1<p;i++){
        cout<<(dp[1][p][i]+p)%p<<" ";
    }
    cout<<(dp[1][p][p-1]+p)%p<<endl;
    return 0;
}