This documentation is automatically generated by online-judge-tools/verification-helper
#define PROBLEM "https://judge.yosupo.jp/problem/matrix_det"
#include<bits/stdc++.h>
using namespace std;
#include"../../../modint.hpp"
#include"../../../Algebra/Field_Matrix.hpp"
int main(){
int N; cin >> N;
Field_Matrix<modint<998244353>> A(N);
cin >> A;
cout << Determinant(A) << endl;
}
#line 1 "verify/yosupo_library_checker/linear_algebra/Determinant.test.cpp"
#define PROBLEM "https://judge.yosupo.jp/problem/matrix_det"
#include<bits/stdc++.h>
using namespace std;
#line 2 "modint.hpp"
template<int mod>
class modint{
public:
int64_t x;
public:
// 初期化
constexpr modint(): x(0) {}
constexpr modint(int64_t a): x((a % mod + mod) % mod) {}
// マイナス元
modint operator-() const { return modint(-x); }
// 加法
modint& operator+=(const modint &b){
if ((x += b.x) >= mod) x -= mod;
return *this;
}
friend modint operator+(const modint &x, const modint &y) { return modint(x) += y; }
// 減法
modint& operator-=(const modint &b){
if ((x += mod - b.x) >= mod) x -= mod;
return *this;
}
friend modint operator-(const modint &x, const modint &y) { return modint(x) -= y; }
// 乗法
modint& operator*=(const modint &b){
(x *= b.x) %= mod;
return *this;
}
friend modint operator*(const modint &x, const modint &y) { return modint(x) *= y; }
// 除法
modint& operator/=(const modint &b){ return (*this) *= b.inverse(); }
friend modint operator/(const modint &x, const modint &y) { return modint(x) /= y; }
modint inverse() const {
int64_t s = 1, t = 0;
int64_t a = x, b = mod;
while (b > 0) {
int64_t q = a / b;
a -= q * b; swap(a, b);
s -= q * t; swap(s, t);
}
assert (a == 1);
return modint(s);
}
// 比較
friend bool operator==(const modint &a, const modint &b) { return (a.x == b.x); }
friend bool operator!=(const modint &a, const modint &b) { return (a.x != b.x); }
// 入力
friend istream &operator>>(istream &is, modint &a) {
is >> a.x;
a.x = (a.x % mod + mod) % mod;
return is;
}
// 出力
friend ostream &operator<<(ostream &os, const modint &a) { return os << a.x; }
};
#line 2 "Algebra/Field_Matrix.hpp"
class SingularMatrixError: private exception{
const char* what() const throw() {
return "非正則行列に関する操作を行いました.";
}
};
template<typename F>
class Field_Matrix{
private:
vector<vector<F>> mat;
public:
int row, col;
public:
Field_Matrix(int row, int col): row(row), col(col){
mat.assign(row, vector<F>(col, F()));
}
Field_Matrix(int row): Field_Matrix(row, row){}
Field_Matrix(vector<vector<F>> &ele): Field_Matrix(ele.size(), ele[0].size()){
for (int i = 0; i < row; i++){
copy(ele[i].begin(), ele[i].end(), mat[i].begin());
}
}
static Field_Matrix Zero_Matrix(int row, int col) { return Field_Matrix(row, col); }
static Field_Matrix Identity_Matrix(int size) {
Field_Matrix A(size);
for (int i = 0; i < size; i++) { A[i][i] = 1; }
return A;
}
// サイズ
pair<int, int> size() { return make_pair(row, col); }
// 正方行列?
bool is_square() const { return row == col; }
// 要素
inline const vector<F> &operator[](int i) const { return mat[i]; }
inline vector<F> &operator[](int i) { return mat[i]; }
// 比較
bool operator==(const Field_Matrix &B) const {
if (row != B.row || col != B.col){ return false; }
for (int i = 0; i < row; i++){
for (int j = 0; j < col; j++){
if ((*this)[i] != B[i]) return false;
}
}
return true;
}
bool operator!=(const Field_Matrix &B) const { return !((*this) == B); }
// マイナス元
Field_Matrix operator-() const {
Field_Matrix A(row, col);
for (int i = 0; i < row; i++){
for (int j = 0; j < col; j++) A[i][j] = -(*this)[i][j];
}
return A;
}
// 加法
Field_Matrix& operator+=(const Field_Matrix &B){
assert (row == B.row && col == B.col);
for (int i = 0; i < row; i++){
for (int j = 0; j < col; j++){
(*this)[i][j] += B[i][j];
}
}
return *this;
}
Field_Matrix operator+(const Field_Matrix &B) const { return Field_Matrix(*this) += B; }
// 減法
Field_Matrix& operator-=(const Field_Matrix &B){
assert (row == B.row && col == B.col);
for (int i = 0; i < row; i++){
for (int j = 0; j < col; j++){
(*this)[i][j] -= B[i][j];
}
}
return *this;
}
Field_Matrix operator-(const Field_Matrix &B) const {return Field_Matrix(*this) -= B; }
// 乗法
Field_Matrix& operator*=(const Field_Matrix &B){
assert (col == B.row);
vector<vector<F>> C(row, vector<F>(B.col, F()));
for (int i = 0; i < row; i++){
for (int k = 0; k < col; k++){
for (int j = 0; j < B.col; j++){
C[i][j] += (*this)[i][k] * B[k][j];
}
}
}
mat.swap(C); col = B.col;
return *this;
}
Field_Matrix operator*(const Field_Matrix &B) const { return Field_Matrix(*this)*=B; }
// スカラー倍
friend Field_Matrix operator*(const F &scaler, const Field_Matrix &rhs){
Field_Matrix res(rhs);
for (int i = 0; i < rhs.row; i++){
for (int j = 0; j < rhs.col; j++) { res[i][j] *= scaler; }
}
return res;
}
// 逆行列
Field_Matrix inverse(){
assert (is_square());
int N = col;
Field_Matrix A(*this), B(N,N);
for (int i = 0; i < N; i++) B[i][i] = F(1);
for (int j = 0; j < N; j++){
if (A[j][j] == 0){
int i = j + 1;
for (; i < N; i++){
if (A[i][j] != 0) break;
}
if (i == N) { throw SingularMatrixError(); }
swap(A[i], A[j]); swap(B[i], B[j]);
}
F a_inv = A[j][j].inverse();
for (int k = 0; k < N; k++){
A[j][k] *= a_inv;
B[j][k] *= a_inv;
}
for (int i = 0; i < N; i++){
if (i == j) { continue; }
F c = A[i][j];
for (int k = 0; k < N; k++){
A[i][k] -= A[j][k] * c;
B[i][k] -= B[j][k] * c;
}
}
}
return B;
}
bool is_regular(){
assert (is_square());
int N = row;
vector<vector<F>> A(N, vector<F>(N));
for (int i = 0; i < N; i++){
copy(mat[i].begin(), mat[i].end(), A[i].begin());
}
for (int j = 0; j < N; j++){
if (A[j][j] == 0){
int i = j + 1;
for (; i < N; i++){
if (A[i][j] != 0) break;
}
if (i == N) return false;
swap(A[i], A[j]);
}
F a_inv = A[j][j].inverse();
for (int i = j + 1; i < N; i++){
F c = -a_inv * A[i][j];
for (int k = 0; k < N; k++){ A[i][k] += c * A[j][k]; }
}
}
return true;
}
// 転置
Field_Matrix transpose(){
Field_Matrix B(col, row);
for (int i = 0; i < col; i++){
for (int j = 0; j < row; j++) B[i][j] = (*this)[j][i];
}
return B;
}
//
bool is_valid(){return (row > 0) && (col > 0);}
// 入力
friend istream &operator>>(istream &is, Field_Matrix &A) {
for (int i = 0; i < A.row; i++){
for (int j = 0; j < A.col; j++){
cin >> A[i][j];
}
}
return is;
}
// 出力
friend ostream &operator<<(ostream &os, const Field_Matrix &A){
for (int i = 0; i < A.row; i++){
for (int j = 0; j < A.col; j++){
cout << (j ? " ": "") << A[i][j];
}
if (i < A.row - 1) cout << "\n";
}
return os;
}
};
template<typename F>
Field_Matrix<F> power(Field_Matrix<F> A, int64_t n){
assert (A.is_square());
if (n == 0) { return Field_Matrix<F>::Identity_Matrix(A.row); }
if (n < 0) { return power(A.inverse(), -n); }
if (n % 2 == 0){
Field_Matrix<F> B = power(A, n / 2);
return B * B;
} else {
Field_Matrix<F> B = power(A, (n - 1) / 2);
return A * B * B;
}
}
// 行列 A の行列式を求める
template<typename F>
F Determinant(const Field_Matrix<F> &A){
assert (A.is_square());
int n = A.row;
F det(1);
Field_Matrix<F> B(A);
for (int j = 0; j < n; j ++){
if (B[j][j] == 0){
int i = j + 1;
for (; i < n; i++) {
if (B[i][j] != 0) { break; }
}
if (i == n) { return F(0); }
swap(B[i], B[j]);
det = -det;
}
F a_inv = B[j][j].inverse();
for (int i = j + 1; i < n; i++){
F c = -a_inv * B[i][j];
for (int k = 0; k < n; k++) { B[i][k] += c * B[j][k]; }
}
det *= B[j][j];
}
return det;
}
#line 9 "verify/yosupo_library_checker/linear_algebra/Determinant.test.cpp"
int main(){
int N; cin >> N;
Field_Matrix<modint<998244353>> A(N);
cin >> A;
cout << Determinant(A) << endl;
}