結果
| 問題 |
No.1907 DETERMINATION
|
| コンテスト | |
| ユーザー |
hitonanode
|
| 提出日時 | 2022-04-14 23:24:57 |
| 言語 | C++23 (gcc 13.3.0 + boost 1.87.0) |
| 結果 |
AC
|
| 実行時間 | 731 ms / 4,000 ms |
| コード長 | 13,770 bytes |
| コンパイル時間 | 2,415 ms |
| コンパイル使用メモリ | 155,588 KB |
| 実行使用メモリ | 17,128 KB |
| 最終ジャッジ日時 | 2024-12-24 12:27:32 |
| 合計ジャッジ時間 | 30,109 ms |
|
ジャッジサーバーID (参考情報) |
judge4 / judge1 |
(要ログイン)
| ファイルパターン | 結果 |
|---|---|
| sample | AC * 4 |
| other | AC * 63 |
ソースコード
#include <cassert>
#include <iostream>
#include <utility>
#include <vector>
using namespace std;
#include <chrono>
#include <random>
struct rand_int_ {
using lint = long long;
mt19937 mt;
rand_int_() : mt(chrono::steady_clock::now().time_since_epoch().count()) {}
lint operator()(lint x) { return this->operator()(0, x); } // [0, x)
lint operator()(lint l, lint r) {
uniform_int_distribution<lint> d(l, r - 1);
return d(mt);
}
} rnd;
// Upper Hessenberg reduction of square matrices
// Complexity: O(n^3)
// Reference:
// http://www.phys.uri.edu/nigh/NumRec/bookfpdf/f11-5.pdf
template <class Tp> void hessenberg_reduction(std::vector<std::vector<Tp>> &M) {
assert(M.size() == M[0].size());
const int N = M.size();
for (int r = 0; r < N - 2; r++) {
int piv = -1;
for (int h = r + 1; h < N; ++h) {
if (M[h][r] != 0) {
piv = h;
break;
}
}
if (piv < 0) continue;
for (int i = 0; i < N; i++) std::swap(M[r + 1][i], M[piv][i]);
for (int i = 0; i < N; i++) std::swap(M[i][r + 1], M[i][piv]);
const auto rinv = Tp(1) / M[r + 1][r];
for (int i = r + 2; i < N; i++) {
const auto n = M[i][r] * rinv;
for (int j = 0; j < N; j++) M[i][j] -= M[r + 1][j] * n;
for (int j = 0; j < N; j++) M[j][r + 1] += M[j][i] * n;
}
}
}
// Characteristic polynomial of matrix M (|xI - M|)
// Complexity: O(n^3)
// R. Rehman, I. C. Ipsen, "La Budde's Method for Computing Characteristic Polynomials," 2011.
template <class Tp> std::vector<Tp> characteristic_poly(std::vector<std::vector<Tp>> M) {
hessenberg_reduction(M);
const int N = M.size();
// p[i + 1] = (Characteristic polynomial of i-th leading principal minor)
std::vector<std::vector<Tp>> p(N + 1);
p[0] = {1};
for (int i = 0; i < N; i++) {
p[i + 1].assign(i + 2, 0);
for (int j = 0; j < i + 1; j++) p[i + 1][j + 1] += p[i][j];
for (int j = 0; j < i + 1; j++) p[i + 1][j] -= p[i][j] * M[i][i];
Tp betas = 1;
for (int j = i - 1; j >= 0; j--) {
betas *= M[j + 1][j];
Tp hb = -M[j][i] * betas;
for (int k = 0; k < j + 1; k++) p[i + 1][k] += hb * p[j][k];
}
}
return p[N];
}
#include <algorithm>
#include <cassert>
#include <cmath>
#include <iterator>
#include <type_traits>
#include <utility>
#include <vector>
namespace matrix_ {
struct has_id_method_impl {
template <class T_> static auto check(T_ *) -> decltype(T_::id(), std::true_type());
template <class T_> static auto check(...) -> std::false_type;
};
template <class T_> struct has_id : decltype(has_id_method_impl::check<T_>(nullptr)) {};
} // namespace matrix_
template <typename T> struct matrix {
int H, W;
std::vector<T> elem;
typename std::vector<T>::iterator operator[](int i) { return elem.begin() + i * W; }
inline T &at(int i, int j) { return elem[i * W + j]; }
inline T get(int i, int j) const { return elem[i * W + j]; }
int height() const { return H; }
int width() const { return W; }
std::vector<std::vector<T>> vecvec() const {
std::vector<std::vector<T>> ret(H);
for (int i = 0; i < H; i++) {
std::copy(elem.begin() + i * W, elem.begin() + (i + 1) * W, std::back_inserter(ret[i]));
}
return ret;
}
operator std::vector<std::vector<T>>() const { return vecvec(); }
matrix() = default;
matrix(int H, int W) : H(H), W(W), elem(H * W) {}
matrix(const std::vector<std::vector<T>> &d) : H(d.size()), W(d.size() ? d[0].size() : 0) {
for (auto &raw : d) std::copy(raw.begin(), raw.end(), std::back_inserter(elem));
}
template <typename T2, typename std::enable_if<matrix_::has_id<T2>::value>::type * = nullptr>
static T2 _T_id() {
return T2::id();
}
template <typename T2, typename std::enable_if<!matrix_::has_id<T2>::value>::type * = nullptr>
static T2 _T_id() {
return T2(1);
}
static matrix Identity(int N) {
matrix ret(N, N);
for (int i = 0; i < N; i++) ret.at(i, i) = _T_id<T>();
return ret;
}
matrix operator-() const {
matrix ret(H, W);
for (int i = 0; i < H * W; i++) ret.elem[i] = -elem[i];
return ret;
}
matrix operator*(const T &v) const {
matrix ret = *this;
for (auto &x : ret.elem) x *= v;
return ret;
}
matrix operator/(const T &v) const {
matrix ret = *this;
const T vinv = _T_id<T>() / v;
for (auto &x : ret.elem) x *= vinv;
return ret;
}
matrix operator+(const matrix &r) const {
matrix ret = *this;
for (int i = 0; i < H * W; i++) ret.elem[i] += r.elem[i];
return ret;
}
matrix operator-(const matrix &r) const {
matrix ret = *this;
for (int i = 0; i < H * W; i++) ret.elem[i] -= r.elem[i];
return ret;
}
matrix operator*(const matrix &r) const {
matrix ret(H, r.W);
for (int i = 0; i < H; i++) {
for (int k = 0; k < W; k++) {
for (int j = 0; j < r.W; j++) ret.at(i, j) += this->get(i, k) * r.get(k, j);
}
}
return ret;
}
matrix &operator*=(const T &v) { return *this = *this * v; }
matrix &operator/=(const T &v) { return *this = *this / v; }
matrix &operator+=(const matrix &r) { return *this = *this + r; }
matrix &operator-=(const matrix &r) { return *this = *this - r; }
matrix &operator*=(const matrix &r) { return *this = *this * r; }
bool operator==(const matrix &r) const { return H == r.H and W == r.W and elem == r.elem; }
bool operator!=(const matrix &r) const { return H != r.H or W != r.W or elem != r.elem; }
bool operator<(const matrix &r) const { return elem < r.elem; }
matrix pow(int64_t n) const {
matrix ret = Identity(H);
bool ret_is_id = true;
if (n == 0) return ret;
for (int i = 63 - __builtin_clzll(n); i >= 0; i--) {
if (!ret_is_id) ret *= ret;
if ((n >> i) & 1) ret *= (*this), ret_is_id = false;
}
return ret;
}
std::vector<T> pow_vec(int64_t n, std::vector<T> vec) const {
matrix x = *this;
while (n) {
if (n & 1) vec = x * vec;
x *= x;
n >>= 1;
}
return vec;
};
matrix transpose() const {
matrix ret(W, H);
for (int i = 0; i < H; i++) {
for (int j = 0; j < W; j++) ret.at(j, i) = this->get(i, j);
}
return ret;
}
// Gauss-Jordan elimination
// - Require inverse for every non-zero element
// - Complexity: O(H^2 W)
template <typename T2, typename std::enable_if<std::is_floating_point<T2>::value>::type * = nullptr>
static int choose_pivot(const matrix<T2> &mtr, int h, int c) noexcept {
int piv = -1;
for (int j = h; j < mtr.H; j++) {
if (mtr.get(j, c) and (piv < 0 or std::abs(mtr.get(j, c)) > std::abs(mtr.get(piv, c))))
piv = j;
}
return piv;
}
template <typename T2, typename std::enable_if<!std::is_floating_point<T2>::value>::type * = nullptr>
static int choose_pivot(const matrix<T2> &mtr, int h, int c) noexcept {
for (int j = h; j < mtr.H; j++) {
if (mtr.get(j, c) != T2()) return j;
}
return -1;
}
matrix gauss_jordan() const {
int c = 0;
matrix mtr(*this);
std::vector<int> ws;
ws.reserve(W);
for (int h = 0; h < H; h++) {
if (c == W) break;
int piv = choose_pivot(mtr, h, c);
if (piv == -1) {
c++;
h--;
continue;
}
if (h != piv) {
for (int w = 0; w < W; w++) {
std::swap(mtr[piv][w], mtr[h][w]);
mtr.at(piv, w) *= -_T_id<T>(); // To preserve sign of determinant
}
}
ws.clear();
for (int w = c; w < W; w++) {
if (mtr.at(h, w) != T()) ws.emplace_back(w);
}
const T hcinv = _T_id<T>() / mtr.at(h, c);
for (int hh = 0; hh < H; hh++)
if (hh != h) {
const T coeff = mtr.at(hh, c) * hcinv;
for (auto w : ws) mtr.at(hh, w) -= mtr.at(h, w) * coeff;
mtr.at(hh, c) = T();
}
c++;
}
return mtr;
}
int rank_of_gauss_jordan() const {
for (int i = H * W - 1; i >= 0; i--) {
if (elem[i] != 0) return i / W + 1;
}
return 0;
}
T determinant_of_upper_triangle() const {
T ret = _T_id<T>();
for (int i = 0; i < H; i++) ret *= get(i, i);
return ret;
}
int inverse() {
assert(H == W);
std::vector<std::vector<T>> ret = Identity(H), tmp = *this;
int rank = 0;
for (int i = 0; i < H; i++) {
int ti = i;
while (ti < H and tmp[ti][i] == 0) ti++;
if (ti == H) {
continue;
} else {
rank++;
}
ret[i].swap(ret[ti]), tmp[i].swap(tmp[ti]);
T inv = _T_id<T>() / tmp[i][i];
for (int j = 0; j < W; j++) ret[i][j] *= inv;
for (int j = i + 1; j < W; j++) tmp[i][j] *= inv;
for (int h = 0; h < H; h++) {
if (i == h) continue;
const T c = -tmp[h][i];
for (int j = 0; j < W; j++) ret[h][j] += ret[i][j] * c;
for (int j = i + 1; j < W; j++) tmp[h][j] += tmp[i][j] * c;
}
}
*this = ret;
return rank;
}
friend std::vector<T> operator*(const matrix &m, const std::vector<T> &v) {
assert(m.W == int(v.size()));
std::vector<T> ret(m.H);
for (int i = 0; i < m.H; i++) {
for (int j = 0; j < m.W; j++) ret[i] += m.get(i, j) * v[j];
}
return ret;
}
friend std::vector<T> operator*(const std::vector<T> &v, const matrix &m) {
assert(int(v.size()) == m.H);
std::vector<T> ret(m.W);
for (int i = 0; i < m.H; i++) {
for (int j = 0; j < m.W; j++) ret[j] += v[i] * m.get(i, j);
}
return ret;
}
std::vector<T> prod(const std::vector<T> &v) const { return (*this) * v; }
std::vector<T> prod_left(const std::vector<T> &v) const { return v * (*this); }
template <class OStream> friend OStream &operator<<(OStream &os, const matrix &x) {
os << "[(" << x.H << " * " << x.W << " matrix)";
os << "\n[column sums: ";
for (int j = 0; j < x.W; j++) {
T s = 0;
for (int i = 0; i < x.H; i++) s += x.get(i, j);
os << s << ",";
}
os << "]";
for (int i = 0; i < x.H; i++) {
os << "\n[";
for (int j = 0; j < x.W; j++) os << x.get(i, j) << ",";
os << "]";
}
os << "]\n";
return os;
}
template <class IStream> friend IStream &operator>>(IStream &is, matrix &x) {
for (auto &v : x.elem) is >> v;
return is;
}
};
#include <atcoder/modint>
using mint = atcoder::modint998244353;
#include <cassert>
#include <iostream>
#include <vector>
// Utility functions for atcoder::static_modint<md>
template <int md> std::istream &operator>>(std::istream &is, atcoder::static_modint<md> &x) {
long long t;
return is >> t, x = t, is;
}
template <int md> std::ostream &operator<<(std::ostream &os, const atcoder::static_modint<md> &x) {
return os << x.val();
}
// atcoder::static_modint<P>, P: prime number
template <typename modint> struct acl_fac {
std::vector<modint> facs, facinvs;
acl_fac(int N) {
assert(-1 <= N and N < modint::mod());
facs.resize(N + 1, 1);
for (int i = 1; i <= N; i++) facs[i] = facs[i - 1] * i;
facinvs.assign(N + 1, facs.back().inv());
for (int i = N; i > 0; i--) facinvs[i - 1] = facinvs[i] * i;
}
modint ncr(int n, int r) const {
if (n < 0 or r < 0 or n < r) return 0;
return facs[n] * facinvs[r] * facinvs[n - r];
}
modint operator[](int i) const { return facs[i]; }
modint finv(int i) const { return facinvs[i]; }
};
acl_fac<mint> fac(1000000);
int main() {
cin.tie(nullptr), ios::sync_with_stdio(false);
int N;
cin >> N;
vector M0(N, vector<mint>(N)), M1(N, vector<mint>(N));
for (auto &vec : M0) {
for (auto &x : vec) {
int v;
cin >> v;
x = v;
}
}
for (auto &vec : M1) {
for (auto &x : vec) {
int v;
cin >> v;
x = v;
}
}
const mint a = rnd(mint::mod());
// M0 + M1(x + a) の行列式を求める
matrix<mint> M0_plus_aM1 = matrix(M0) + matrix(M1) * a;
auto M_inv = M0_plus_aM1;
int rank = M_inv.inverse();
if (rank < N) {
for (int i = 0; i <= N; ++i) cout << 0 << '\n';
return 0;
}
mint det = M0_plus_aM1.gauss_jordan().determinant_of_upper_triangle();
cerr << det.val() << '\n';
auto poly = characteristic_poly((-matrix(M1) * M_inv).vecvec());
reverse(poly.begin(), poly.end());
for (auto e : poly) cerr << e << ' ';
cerr << endl;
vector<mint> ret(N + 1);
for (int d = 0; d <= N; ++d) {
// poly[d] * (x + a)^d
for (int e = 0; e <= d; ++e) ret[e] += poly[d] * fac.ncr(d, e) * mint(-a).pow(d - e) * det;
}
for (auto x : ret) cout << x.val() << '\n';
}
hitonanode