@@ -14,38 +14,73 @@ const int mod = 998244353;
14
14
using base = modular<mod>;
15
15
using polyn = poly_t <base>;
16
16
17
+ template <bool reduce = false >
18
+ auto frobenius_basis (auto const & A) {
19
+ assert (A.n () == A.m ());
20
+ size_t n = A.n ();
21
+ struct krylov {
22
+ vector<vec<base>> basis;
23
+ poly_t <base> rec;
24
+ };
25
+ vector<krylov> blocks;
26
+ vector<vec<base>> reduced;
27
+ while (size (reduced) < n) {
28
+ auto generate_block = [&](auto x) {
29
+ krylov block;
30
+ while (true ) {
31
+ vec<base> y = x | vec<base>::ei (n + 1 , size (reduced));
32
+ for (auto &it: reduced) {
33
+ y.reduce_by (it);
34
+ }
35
+ y.normalize ();
36
+ if (vec<base>(y[slice (0 , n, 1 )]) == vec<base>(n)) {
37
+ block.rec = vector<base>(
38
+ begin (y) + n + size (reduced) - size (block.basis ),
39
+ begin (y) + n + size (reduced) + 1
40
+ );
41
+ return std::pair{block, vec<base>(y[slice (n, n, 1 )])};
42
+ } else {
43
+ block.basis .push_back (x);
44
+ reduced.push_back (y);
45
+ x = A.apply (x);
46
+ }
47
+ }
48
+ };
49
+ auto [block, full_rec] = generate_block (vec<base>::random (n));
50
+ if constexpr (reduce) {
51
+ if (vec<base>(full_rec[slice (0 , size (reduced), 1 )]) != vec<base>(size (reduced))) {
52
+ auto x = block.basis [0 ];
53
+ size_t start = 0 ;
54
+ for (auto &[basis, rec]: blocks) {
55
+ polyn cur_rec = vector<base>(
56
+ begin (full_rec) + start, begin (full_rec) + start + rec.deg ()
57
+ );
58
+ auto shift = cur_rec / block.rec ;
59
+ for (int j = 0 ; j <= shift.deg (); j++) {
60
+ x.add_scaled (basis[j], shift[j]);
61
+ }
62
+ start += rec.deg ();
63
+ }
64
+ reduced.erase (begin (reduced) + start, end (reduced));
65
+ tie (block, full_rec) = generate_block (x.normalize ());
66
+ }
67
+ }
68
+ blocks.push_back (block);
69
+ }
70
+ return blocks;
71
+ }
72
+
17
73
void solve () {
18
74
size_t n;
19
75
cin >> n;
20
76
matrix<base> A (n);
21
77
A.read ();
22
- vector<vec<base>> basis;
23
- auto x = vec<base>::random (n);
24
- size_t degree = 0 ;
25
- polyn ans = base (1 );
26
- while (size (basis) <= n) {
27
- auto y = x | vec<base>::ei (n + 1 , size (basis));
28
- for (auto &it: basis) {
29
- y.reduce_by (it);
30
- }
31
- y.normalize ();
32
- if (vec<base>(y[slice (0 , n, 1 )]) == vec<base>(n)) {
33
- vector<base> cur (begin (y) + n + size (basis) - degree,
34
- begin (y) + n + size (basis) + 1 );
35
- ans *= polyn (cur);
36
- degree = 0 ;
37
- if (size (basis) < n) {
38
- x = vec<base>::random (n);
39
- } else {
40
- break ;
41
- }
42
- } else {
43
- basis.push_back (y);
44
- x = A.apply (x);
45
- degree++;
46
- }
78
+ auto blocks = frobenius_basis (A);
79
+ polyn res (1 );
80
+ for (auto &[basis, rec]: blocks) {
81
+ res *= rec;
47
82
}
48
- ans .print ();
83
+ res .print ();
49
84
}
50
85
51
86
signed main () {
@@ -57,4 +92,4 @@ signed main() {
57
92
while (t--) {
58
93
solve ();
59
94
}
60
- }
95
+ }
0 commit comments