Skip to content

Commit

Permalink
Merge pull request #1249 from maspypy/frobenius
Browse files Browse the repository at this point in the history
テストケース追加(1153)
  • Loading branch information
hos-lyric authored Sep 23, 2024
2 parents f46b86d + 4849cc9 commit 4fb527c
Show file tree
Hide file tree
Showing 6 changed files with 479 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,216 @@
#include <cstdlib>
#include <cstdio>
#include <cassert>
#include <iostream>
#include "random.h"
#include "../params.h"

using namespace std;

using ll = long long;
using u32 = unsigned int;
using u64 = unsigned long long;

template <class T>
using vc = vector<T>;
template <class T>
using vvc = vector<vc<T>>;

#define FOR1(a) for (ll _ = 0; _ < ll(a); ++_)
#define FOR2(i, a) for (ll i = 0; i < ll(a); ++i)
#define FOR3(i, a, b) for (ll i = a; i < ll(b); ++i)
#define FOR4(i, a, b, c) for (ll i = a; i < ll(b); i += (c))
#define FOR1_R(a) for (ll i = (a)-1; i >= ll(0); --i)
#define FOR2_R(i, a) for (ll i = (a)-1; i >= ll(0); --i)
#define FOR3_R(i, a, b) for (ll i = (b)-1; i >= ll(a); --i)
#define overload4(a, b, c, d, e, ...) e
#define overload3(a, b, c, d, ...) d
#define FOR(...) overload4(__VA_ARGS__, FOR4, FOR3, FOR2, FOR1)(__VA_ARGS__)
#define FOR_R(...) overload3(__VA_ARGS__, FOR3_R, FOR2_R, FOR1_R)(__VA_ARGS__)

#define all(x) x.begin(), x.end()
#define len(x) ll(x.size())
#define elif else if

template <int mod>
struct modint {
static constexpr u32 umod = u32(mod);
static_assert(umod < u32(1) << 31);
u32 val;

static modint raw(u32 v) {
modint x;
x.val = v;
return x;
}
constexpr modint() : val(0) {}
constexpr modint(ll x) : val((x %= mod) < 0 ? x + mod : x){};
modint &operator+=(const modint &p) {
if ((val += p.val) >= umod) val -= umod;
return *this;
}
modint &operator-=(const modint &p) {
if ((val += umod - p.val) >= umod) val -= umod;
return *this;
}
modint &operator*=(const modint &p) {
val = u64(val) * p.val % umod;
return *this;
}
modint &operator/=(const modint &p) {
*this *= p.inverse();
return *this;
}
modint operator-() const { return modint::raw(val ? mod - val : u32(0)); }
modint operator+(const modint &p) const { return modint(*this) += p; }
modint operator-(const modint &p) const { return modint(*this) -= p; }
modint operator*(const modint &p) const { return modint(*this) *= p; }
modint operator/(const modint &p) const { return modint(*this) /= p; }
bool operator==(const modint &p) const { return val == p.val; }
bool operator!=(const modint &p) const { return val != p.val; }
modint inverse() const {
int a = val, b = mod, u = 1, v = 0, t;
while (b > 0) {
t = a / b;
swap(a -= t * b, b), swap(u -= t * v, v);
}
return modint(u);
}
static constexpr int get_mod() { return mod; }
};

using modint998 = modint<998244353>;

template <typename T>
vc<vc<T>> matrix_mul(const vc<vc<T>> &A, const vc<vc<T>> &B, int N1 = -1, int N2 = -1, int N3 = -1) {
if (N1 == -1) { N1 = len(A), N2 = len(B), N3 = len(B[0]); }
vvc<T> b(N2, vc<T>(N3));
FOR(i, N2) FOR(j, N3) b[j][i] = B[i][j];
vvc<T> C(N1, vc<T>(N3));
FOR(n, N1) FOR(m, N2) FOR(k, N3) C[n][k] += A[n][m] * b[k][m];
return C;
}

// (det, invA) をかえす
template <typename T>
pair<T, vc<vc<T>>> matrix_inv(vc<vc<T>> A) {
T det = 1;
int N = len(A);
vvc<T> B(N, vc<T>(N));
FOR(n, N) B[n][n] = 1;
FOR(i, N) {
FOR(k, i, N) if (A[k][i] != 0) {
if (k != i) {
swap(A[i], A[k]), swap(B[i], B[k]);
det = -det;
}
break;
}
if (A[i][i] == 0) return {T(0), {}};
T c = T(1) / A[i][i];
det *= A[i][i];
FOR(j, i, N) A[i][j] *= c;
FOR(j, N) B[i][j] *= c;
FOR(k, N) if (i != k) {
T c = A[k][i];
FOR(j, i, N) A[k][j] -= A[i][j] * c;
FOR(j, N) B[k][j] -= B[i][j] * c;
}
}
return {det, B};
}

using mint = modint998;

void out(int n, vector<vector<mint>> a) {
printf("%d\n", n);
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
printf("%d", a[i][j].val);
if (j + 1 != n) printf(" ");
}
printf("\n");
}
}

vc<mint> random_poly(int n, Random &gen) {
vc<mint> f(n + 1);
f[n] = 1;
FOR(i, n) f[i] = gen.uniform<int>(0, mint::get_mod() - 1);
return f;
}

vvc<mint> gen_mat(vc<int> S, Random &gen) {
sort(all(S));
int B = len(S);
vvc<mint> poly(B);
poly[0] = random_poly(S[0], gen);
FOR(b, 1, B) {
vc<mint> f = poly[b - 1];
vc<mint> g = random_poly(S[b] - S[b - 1], gen);
vc<mint> F(S[b] + 1);
FOR(i, len(f)) FOR(j, len(g)) F[i + j] += f[i] * g[j];
poly[b] = F;
}
// desc
reverse(all(S));
reverse(all(poly));
int N = 0;
for (auto &x: S) N += x;
int s = 0;
vvc<mint> A(N, vc<mint>(N));
FOR(b, B) {
int d = S[b];
FOR(i, d - 1) A[s + i + 1][s + i] = 1;
FOR(i, d) A[s + i][s + d - 1] = -poly[b][i];
s += d;
}
assert(s == N);
// inv(P) A P
while (1) {
vvc<mint> P(N, vc<mint>(N));
FOR(i, N) FOR(j, N) P[i][j] = gen.uniform<int>(0, mint::get_mod() - 1);
auto [det, IP] = matrix_inv<mint>(P);
if (det == mint(0)) continue;
A = matrix_mul<mint>(IP, A);
A = matrix_mul<mint>(A, P);
return A;
}
}

int main(int, char *argv[]) {
long long seed = atoll(argv[1]);
auto gen = Random(seed);

int N = N_MAX;

if (0 <= seed && seed < 5) {
int ks[] = {1, 2, 5, 10, 20};
int K = ks[seed];
vc<int> S;
int now = 0;
while (now < N) {
int k = gen.uniform<int>(1, K);
if (now + k > N) continue;
S.emplace_back(k), now += k;
}
vvc<mint> A = gen_mat(S, gen);
out(N, A);
}
elif (5 <= seed && seed < 10) {
int ks[] = {1, 2, 5, 10, 20};
int K = ks[seed - 5];
vc<int> cut = gen.choice(K - 1, 1, N - 1);
cut.insert(cut.begin(), 0);
cut.emplace_back(N);
assert(len(cut) == K + 1);
vc<int> S(K);
FOR(i, K) S[i] = cut[i + 1] - cut[i];
vvc<mint> A = gen_mat(S, gen);
out(N, A);
}
else {
assert(0);
}
return 0;
}
20 changes: 20 additions & 0 deletions linear_algebra/characteristic_polynomial/hash.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,26 @@
"max_random_03.out": "a4c8f74e7dfa526e8d743b338e655b47490f332fee902edcde946f5f134f3081",
"max_zero_00.in": "16924b8f7776ce2f41d80b8d00e45330362bfc97033bb561b276b841358a2c91",
"max_zero_00.out": "14a4ee7ad7a4583598ccc1bd8226f8166304e37da7e0f5c2aff98b58e9db8379",
"nontrivial_frobenius_form_00.in": "eae9b978d16e992fcc24a15832867c099fbc5f9f17fa071c9c7b7e6b7f877873",
"nontrivial_frobenius_form_00.out": "9030384be07b7895d08f2cba326a15539341c220a5eeba264654d40ea948cf76",
"nontrivial_frobenius_form_01.in": "306a2fa13dd29ee02778336807752d1b192084edad79fe55b9038b7d3983ed1d",
"nontrivial_frobenius_form_01.out": "edaa83156427452cda981cd319a7be00e7799299ba770aa546c356d679dd2a34",
"nontrivial_frobenius_form_02.in": "d996b0b13a10974c430c2db6b32878417c5e769b16a11000c87f993587a29cf0",
"nontrivial_frobenius_form_02.out": "8aad40349a5afb761824f2962beda8d400368589caa1da490ce525da6d7cb61c",
"nontrivial_frobenius_form_03.in": "2da9a3010ce15fbf21077d3ee02485df0aeb4f1ce9c08d590794197b46c4ab85",
"nontrivial_frobenius_form_03.out": "e18d2f00a6da1c096cfa0d426186ecfff79bd3092a707d428a4873ddca3f794f",
"nontrivial_frobenius_form_04.in": "5c3a5835f52f62a0e5a39ad820f77dd3a2895ea3fa3b8d9a280161e78808123e",
"nontrivial_frobenius_form_04.out": "bf06b98bf4333294e283210a8ea84b6b0d4b20cf40bd61a764fdb3614208b1b8",
"nontrivial_frobenius_form_05.in": "70ae11941fb9eab5a7122d33f9a0c6cf6c3e8510b13c998136e82347a21f5cc7",
"nontrivial_frobenius_form_05.out": "3829e65f3445085e9a7b4a959e856dcbac27bdf00208cd1c48274e59c3867cb6",
"nontrivial_frobenius_form_06.in": "47a825c4a3c28630770da597593e0e00e43eef54f52368433606282064b6a8a8",
"nontrivial_frobenius_form_06.out": "9453721911977759868f9b3a41ad24ebdbada9f6c5c16ab4f22b8a01a94dacba",
"nontrivial_frobenius_form_07.in": "80ca6e0ff0a99e674573c5b85cfa02a444349c7232dd13068301102d73ab8314",
"nontrivial_frobenius_form_07.out": "0bbd86d023320cfbdd81921073a5c99b8d8a343be5f91190e8939bb17062acb0",
"nontrivial_frobenius_form_08.in": "7815ed6591321105c99262d0de8f50eb9f2d48444c2035967cfdfbfbf29c5a02",
"nontrivial_frobenius_form_08.out": "3c3f9b8824cdcf6be7ce9e1131f96ba8f73904e61692faa3ec50d6d68f9031bc",
"nontrivial_frobenius_form_09.in": "c5c9e32af2630ba239db00dda4da74ddeebaabf011397500a2bdf942c833a07a",
"nontrivial_frobenius_form_09.out": "f46c10e92105bbd00f3f3de8c28f8f3a78b9f246fd89a16e26332f0cf79e2199",
"small_multiple_root_00.in": "554216c7290421befe67c09fbd4ea1efdbf87823e342051c7137883a06ade0b3",
"small_multiple_root_00.out": "71f8c4c82caeb9419bf95fd5904524ce13a84b9b0580a0545865d668bf96a501",
"small_multiple_root_01.in": "2dbddc26ef78aed6151ba00a841ce96ba7fe8ee7ba1e89ee94d9791ed67f2dd5",
Expand Down
4 changes: 4 additions & 0 deletions linear_algebra/characteristic_polynomial/info.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,10 @@ forum = "https://github.com/yosupo06/library-checker-problems/issues/665"
[[tests]]
name = "small_multiple_root.in"
number = 2
[[tests]]
name = "nontrivial_frobenius_form.cpp"
number = 10

[[solutions]]
name = "n_4.cpp"
expect = "RE"
Expand Down
Loading

0 comments on commit 4fb527c

Please sign in to comment.