#include #include using namespace std; using namespace atcoder; typedef long long int ll; typedef long double ld; #define FOR(i,l,r) for(ll i=l;i=l;i--) #define RREP(i,n) RFOR(i,0,n) #define ALL(x) x.begin(),x.end() #define PA pair #define F first #define S second #define BS(A,x) binary_search(ALL(A),x) #define LB(A,x) (ll)(lower_bound(ALL(A),x)-A.begin()) #define UB(A,x) (ll)(upper_bound(ALL(A),x)-A.begin()) #define COU(A,x) (UB(A,x)-LB(A,x)) templateusing min_priority_queue=priority_queue,greater>; //using mint=modint1000000007; using mint=modint998244353; void chmax(ll&a,ll b){a=max(a,b);} void chmin(ll&a,ll b){a=min(a,b);} void print(vectorA){REP(i,A.size()){if(i)cout<<" ";cout< class Matrix { private: vector> A; T __cofactor(const vector>& coA) const { /* 各余因子の計算を再帰的にする */ if (coA.size() == 1) return coA[0][0]; if (coA.size() == 2) { return coA[0][0]*coA[1][1]-coA[0][1]*coA[1][0]; } T res = 0; for (int col2=0; col2> cocoA(coA.size()-1); for (int row=1; rowrow = row; this->col = col; this->A.resize(row); for(size_t i=0; iA[i].resize(col); } vector& operator[](const size_t i) { return this->A[i]; } Matrix& operator+=(Matrix other) { for(size_t i=0; irow; i++) { for(size_t j=0; jcol; j++) { this->A[i][j] += other[i][j]; } } return *this; } Matrix operator+(const Matrix other) const { return Matrix(*this) += other; } Matrix& operator+=(const double a) { /* 各要素にaを足す */ for (size_t i=0; irow; i++) { for (size_t j=0; jcol; j++) { this->A[i][j] += a; } } return *this; } Matrix operator+(const double a) const { return Matrix(*this) += a; } Matrix& operator-=(Matrix other) { for(size_t i=0; irow; i++) { for(size_t j=0; jcol; j++) { this->A[i][j] -= other[i][j]; } } return *this; } Matrix operator-(const Matrix other) const { return Matrix(*this) -= other; } Matrix operator-() const { Matrix res(this->row, this->col); for (size_t i=0; irow; i++) { for (size_t j=0; jcol; j++) { res[i][j] = -this->A[i][j]; } } return res; } Matrix& operator-=(const double a) { /* 各要素にaを引く */ for (size_t i=0; irow; i++) { for (size_t j=0; jcol; j++) { this->A[i][j] -= a; } } return *this; } Matrix operator-(const double a) const { return Matrix(*this) -= a; } Matrix& operator*=(Matrix other) { /* NxN行列 x NxN行列 の積を求める */ if (!(this->row==this->col && other.row==other.col && this->row==other.row)) throw matrix_product_error(); vector> res(this->row, vector(this->col, 0)); for(size_t i=0; icol; j++) { for (size_t k=0; kcol; k++) { res[i][j] += this->A[i][k]*other[k][j]; } } } this->A = res; return *this; } Matrix operator*(Matrix other) const { /* ixk行列 * kxj行列 の積を求める */ if (this->col!=other.row) throw matrix_product_error(); Matrix res(this->row, other.col); for (size_t i=0; irow; i++) { for (size_t j=0; jcol; k++) { res[i][j] += this->A[i][k]*other[k][j]; } } } return res; } Matrix& operator*=(const double a) { /* 各要素にaをかける */ for (size_t i=0; irow; i++) { for (size_t j=0; jcol; j++) { this->A[i][j] *= a; } } return *this; } Matrix operator*(const double a) const { return Matrix(*this) *= a; } void print() { /* 行列の状態を表示する */ string format; if (typeid(T)==typeid(int)) format = "%*d"s; else if (typeid(T)==typeid(unsigned int) || typeid(T)==typeid(unsigned short)) format = "%*u"s; else if (typeid(T)==typeid(long)) format = "%*ld"s; else if (typeid(T)==typeid(unsigned long)) format = "%*lu"s; else if (typeid(T)==typeid(long long)) format = "%*lld"s; else if (typeid(T)==typeid(unsigned long long)) format = "%*llu"s; else if (typeid(T)==typeid(short)) format = "%*f"s; else if (typeid(T)==typeid(double)) format = "%*lf"s; else if (typeid(T)==typeid(long double)) format = "%*LF"s; else throw print_format_error(); int len = 0; for (size_t i=0; irow; i++) { for (size_t j=0; jcol; j++) { string str = to_string(this->A[i][j]); len = max(len, (int)str.size()); } } printf("[["); for (size_t i=0; irow; i++) { for (size_t j=0; jcol; j++) { printf(format.c_str(), len, this->A[i][j]); if (j!=this->col-1) printf(", "); else printf("]"); } if (i!=this->row-1) printf(",\n "); else printf("]\n"); } } T det() const { /* 行列式を計算して返す */ if (this->row!=this->col) throw determinant_error(); return this->__cofactor(this->A); } Matrix dot(const Matrix B) const { /* ドット積(内積)計算をする */ return Matrix(*this) * B; } Matrix inv() const { /* 逆行列を返す(掃き出し法) */ if (!(this->row==this->col)) throw inversion_error(); size_t N = this->row; Matrix A = *this; Matrix invA(N, N); for (size_t i=0; i>N; MatrixM0(N,N),M1(N,N); REP(i,N)REP(j,N){ll x;cin>>x;M0[i][j]=x;} REP(i,N)REP(j,N){ll x;cin>>x;M1[i][j]=x;} vectorA(N+1); REP(x,N+1){ MatrixM(N,N); REP(i,N)REP(j,N)M[i][j]=M0[i][j]+M1[i][j]*x; A[x]=M.det(); } vectorans(N+1),K(N+1,1); FOR(i,1,N+1)K[i]=i*K[i-1]; REP(i,N+1){ vectorDP(N+1); DP[0]=1; REP(j,N+1)if(i!=j){ RREP(k,N)DP[k+1]=DP[k]-j*DP[k+1]; DP[0]=-j*DP[0]; } REP(j,N+1){ if((N-i)%2)ans[j]-=DP[j]*A[i]/K[N-i]/K[i]; else ans[j]+=DP[j]*A[i]/K[N-i]/K[i]; } } REP(i,N+1)cout<