library_for_cpp

This documentation is automatically generated by online-judge-tools/verification-helper

View the Project on GitHub Kazun1998/library_for_cpp

:heavy_check_mark: verify/yosupo_library_checker/linear_algebra/Determinant.test.cpp

Depends on

Code

#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;
}
Back to top page