using MODint = ModInt<MOD>; using Varray = vector<vector<MODint>>;
structMatrix { int n , m; Varray v;
voidprint()const{ cout << "DEBUG:" << endl; for (int i = 1 ; i <= n ; i++) { for (int j = 1 ; j <= m ; j++) { cout << v[i][j] << ' '; } cout << endl; } cout << endl; }
Matrix(int _n , int _m) { n = _n , m = _m; v = Varray(n + 1 , vector<MODint>(m + 1 , 0)); }
Matrix getT()const{ Matrix ret(m , n);
for (int i = 1 ; i <= n ; i++) { for (int j = 1 ; j <= m ; j++) { ret.v[j][i] = v[i][j]; } } return ret; }
Matrix operator *(const MODint &k) const { Matrix ret = *this; for (int i = 1 ; i <= n ; i++) { for (int j = 1 ; j <= m ; j++) { ret.v[i][j] *= k; } } return ret; }
Matrix operator *(const Matrix &rhs) const { Matrix ret(n , rhs.m); for (int i = 1 ; i <= n ; i++) { for (int k = 1 ; k <= m ; k++) { if (v[i][k] == 0) continue; for (int j = 1 ; j <= rhs.m ; j++) { ret.v[i][j] += v[i][k] * rhs.v[k][j]; } } } return ret; }
pair<pair<int , int> , Matrix> gauss(int &swap_cnt) const { int r = 0 , p = 0; Matrix cur = *this; for (int i = 1 ; i <= n ; i++) { for (int j = i ; j <= n ; j++) { if (cur.v[j][i] != 0) { if (i != j) { swap(cur.v[i] , cur.v[j]); swap_cnt++; } break; } } if (cur.v[i][i] == 0) { p = i; continue; } r++; for (int j = i + 1 ; j <= n ; j++) { if (cur.v[j][i] == 0) { continue; } MODint d = cur.v[j][i] / cur.v[i][i]; for (int k = i ; k <= m ; k++) { cur.v[j][k] -= d * cur.v[i][k]; } } } return {{r , p} , cur}; }
MODint getval()const{ MODint ans = 1; Matrix cur(n , m); for (int i = 1 ; i <= n ; i++) { for (int j = 1 ; j <= m ; j++) { cur.v[i][j] = v[i][j]; } } for (int i = 1 ; i <= n ; i++) { for (int j = i ; j <= n ; j++) { if (cur.v[j][i] != 0) { swap(cur.v[i] , cur.v[j]); ans *= -1; break; } } for (int j = i + 1 ; j <= n ; j++) { if (cur.v[j][i] == 0) { continue; } MODint d = cur.v[j][i] / cur.v[i][i]; for (int k = i ; k <= n ; k++) { cur.v[j][k] -= d * cur.v[i][k]; } } } for (int i = 1 ; i <= n ; i++) { ans *= cur.v[i][i]; } return ans; }
Matrix getinv()const{ Matrix cur(n , n + n); for (int i = 1 ; i <= n ; i++) { for (int j = 1 ; j <= n ; j++) { cur.v[i][j] = v[i][j]; } cur.v[i][i + n] = 1; } for (int i = 1 ; i <= n ; i++) { for (int j = i ; j <= n ; j++) { if (cur.v[j][i] != 0) { swap(cur.v[j] , cur.v[i]); break; } } MODint d = 1 / cur.v[i][i]; for (int j = i ; j <= n + n ; j++) { cur.v[i][j] *= d; } for (int j = 1 ; j <= n ; j++) { if (i == j) continue; MODint d = cur.v[j][i]; for (int k = i ; k <= n + n ; k++) { cur.v[j][k] -= d * cur.v[i][k]; } } } Matrix ret(n , n); for (int i = 1 ; i <= n ; i++) { for (int j = 1 ; j <= n ; j++) { ret.v[i][j] = cur.v[i][j + n]; } } return ret; }
Matrix getR(int r)const{ Matrix ret(n - 1 , m); int R = 0 , C = 0; for (int i = 1 ; i <= n ; i++) { if (i == r) continue; R++ , C = 0; for (int j = 1 ; j <= n ; j++) { C++; ret.v[R][C] = v[i][j]; } } return ret; }
Matrix getRC(int r , int c)const{ Matrix ret(n - 1 , n - 1); int R = 0 , C = 0; for (int i = 1 ; i <= n ; i++) { if (i == r) continue; R++ , C = 0; for (int j = 1 ; j <= n ; j++) { if (j == c) continue; C++; ret.v[R][C] = v[i][j]; } } return ret; }
Matrix getC(int c)const{ Matrix ret(n , m - 1); for (int i = 1 ; i <= n ; i++) { int C = 0; for (int j = 1 ; j <= m ; j++) { if (j == c) continue; C++; ret.v[i][C] = v[i][j]; } } return ret; }
MODint getval_H()const{ // Hessenberg MODint ans = 1; Matrix cur = *this; for (int i = 1 ; i + 1 <= n ; i++) { if (cur.v[i + 1][i] == 0) continue; if (cur.v[i][i] == 0) { swap(cur.v[i] , cur.v[i + 1]); ans *= -1; } MODint d = cur.v[i + 1][i] / cur.v[i][i]; for (int j = i ; j <= n ; j++) { cur.v[i + 1][j] -= d * cur.v[i][j]; } } for (int i = 1 ; i <= n ; i++) { ans *= cur.v[i][i]; } return ans; }
Matrix getadj(int type = 0){ int swap_cnt = 0; auto P = gauss(swap_cnt);
int r = P.first.first , p = P.first.second; auto mat = P.second;
if (r < n - 1) { returnMatrix(n , n); } elseif (r == n - 1) { Matrix ans(n , n); Matrix t = getR(p);
int swap_cnt2 = 0; auto PI = t.gauss(swap_cnt2); auto M = PI.second; for (int i = 1 ; i <= p ; i++) { auto M1 = M.getC(i); ans.v[p][i] = M1.getval_H(); if ((p + i) % 2 == 1) { ans.v[p][i] = -ans.v[p][i]; } if (swap_cnt2 % 2 == 1) { ans.v[p][i] = -ans.v[p][i]; } }
if (type == 0) { // Laplacian for (int i = p - 1 ; i >= 1 ; i--) { for (int j = 1 ; j <= n ; j++) { ans.v[i][j] = ans.v[i + 1][j]; } } ans = ans.getT(); } else { } return ans; } else { // r == n returngetinv() * getval(); } } };