From f7a3c9a9ae7b1548bf8e4dd4653ebb160f596134 Mon Sep 17 00:00:00 2001 From: Oleksandr Kulkov Date: Sun, 27 Oct 2024 13:56:23 +0100 Subject: [PATCH 1/5] Add adjugate_matrix --- linear_algebra/adjugate_matrix/checker.cpp | 62 +++ .../adjugate_matrix/gen/almost_identity.cpp | 25 ++ .../gen/almost_perm_max_random.cpp | 28 ++ .../adjugate_matrix/gen/anti55588_00.in | 4 + .../adjugate_matrix/gen/example_00.in | 4 + .../adjugate_matrix/gen/example_01.in | 4 + .../adjugate_matrix/gen/example_02.in | 3 + .../gen/highrank_max_random.cpp | 49 +++ .../gen/lowrank_max_random.cpp | 60 +++ .../adjugate_matrix/gen/max_random.cpp | 30 ++ .../adjugate_matrix/gen/perm_max_random.cpp | 26 ++ linear_algebra/adjugate_matrix/gen/random.cpp | 30 ++ .../adjugate_matrix/gen/signed_overflow.cpp | 27 ++ .../adjugate_matrix/gen/unsigned_overflow.cpp | 32 ++ linear_algebra/adjugate_matrix/hash.json | 68 ++++ linear_algebra/adjugate_matrix/info.toml | 42 ++ .../adjugate_matrix/sol/correct.cpp | 362 ++++++++++++++++++ linear_algebra/adjugate_matrix/task.md | 49 +++ linear_algebra/adjugate_matrix/verifier.cpp | 20 + 19 files changed, 925 insertions(+) create mode 100644 linear_algebra/adjugate_matrix/checker.cpp create mode 100644 linear_algebra/adjugate_matrix/gen/almost_identity.cpp create mode 100644 linear_algebra/adjugate_matrix/gen/almost_perm_max_random.cpp create mode 100644 linear_algebra/adjugate_matrix/gen/anti55588_00.in create mode 100644 linear_algebra/adjugate_matrix/gen/example_00.in create mode 100644 linear_algebra/adjugate_matrix/gen/example_01.in create mode 100644 linear_algebra/adjugate_matrix/gen/example_02.in create mode 100644 linear_algebra/adjugate_matrix/gen/highrank_max_random.cpp create mode 100644 linear_algebra/adjugate_matrix/gen/lowrank_max_random.cpp create mode 100644 linear_algebra/adjugate_matrix/gen/max_random.cpp create mode 100644 linear_algebra/adjugate_matrix/gen/perm_max_random.cpp create mode 100644 linear_algebra/adjugate_matrix/gen/random.cpp create mode 100644 linear_algebra/adjugate_matrix/gen/signed_overflow.cpp create mode 100644 linear_algebra/adjugate_matrix/gen/unsigned_overflow.cpp create mode 100644 linear_algebra/adjugate_matrix/hash.json create mode 100644 linear_algebra/adjugate_matrix/info.toml create mode 100644 linear_algebra/adjugate_matrix/sol/correct.cpp create mode 100644 linear_algebra/adjugate_matrix/task.md create mode 100644 linear_algebra/adjugate_matrix/verifier.cpp diff --git a/linear_algebra/adjugate_matrix/checker.cpp b/linear_algebra/adjugate_matrix/checker.cpp new file mode 100644 index 000000000..6a66d5330 --- /dev/null +++ b/linear_algebra/adjugate_matrix/checker.cpp @@ -0,0 +1,62 @@ +// https://github.com/MikeMirzayanov/testlib/blob/master/checkers/wcmp.cpp + +// The MIT License (MIT) + +// Copyright (c) 2015 Mike Mirzayanov + +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: + +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. + +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#include "testlib.h" + +using namespace std; + +int main(int argc, char * argv[]) +{ + setName("compare sequences of tokens"); + registerTestlibCmd(argc, argv); + + int n = 0; + string j, p; + + while (!ans.seekEof() && !ouf.seekEof()) + { + n++; + + ans.readWordTo(j); + ouf.readWordTo(p); + + if (j != p) + quitf(_wa, "%d%s words differ - expected: '%s', found: '%s'", n, englishEnding(n).c_str(), compress(j).c_str(), compress(p).c_str()); + } + + if (ans.seekEof() && ouf.seekEof()) + { + if (n == 1) + quitf(_ok, "\"%s\"", compress(j).c_str()); + else + quitf(_ok, "%d tokens", n); + } + else + { + if (ans.seekEof()) + quitf(_wa, "Participant output contains extra tokens"); + else + quitf(_wa, "Unexpected EOF in the participants output"); + } +} diff --git a/linear_algebra/adjugate_matrix/gen/almost_identity.cpp b/linear_algebra/adjugate_matrix/gen/almost_identity.cpp new file mode 100644 index 000000000..52bc26b4b --- /dev/null +++ b/linear_algebra/adjugate_matrix/gen/almost_identity.cpp @@ -0,0 +1,25 @@ +#include +#include "random.h" +#include "../params.h" + +using namespace std; + +int main(int, char* argv[]) { + long long seed = atoll(argv[1]); + auto gen = Random(seed); + + int n = N_MAX; + vector> a(n, vector(n)); + for (int i = 0; i < n; i++) { + a[i][i] = 1; + } + int t = gen.uniform(0, n - 1); + a[t][t] = 0; + printf("%d\n", n); + for (int i = 0; i < n; i++) { + for (int j = 0; j < n; j++) { + printf("%d%c", a[i][j], " \n"[j + 1 == n]); + } + } + return 0; +} diff --git a/linear_algebra/adjugate_matrix/gen/almost_perm_max_random.cpp b/linear_algebra/adjugate_matrix/gen/almost_perm_max_random.cpp new file mode 100644 index 000000000..d2d71ff2d --- /dev/null +++ b/linear_algebra/adjugate_matrix/gen/almost_perm_max_random.cpp @@ -0,0 +1,28 @@ +#include +#include "random.h" +#include "../params.h" + +using namespace std; + +int main(int, char* argv[]) { + + + long long seed = atoll(argv[1]); + auto gen = Random(seed); + + int n = gen.uniform(N_MAX - 10, N_MAX); + vector> a(n, vector(n)); + vector p = gen.perm(n); + for (int i = 0; i < n; i++) { + a[i][p[i]] = gen.uniform(0, MOD - 1); + } + int t = gen.uniform(0, n - 1); + a[t][p[t]] = 0; + printf("%d\n", n); + for (int i = 0; i < n; i++) { + for (int j = 0; j < n; j++) { + printf("%d%c", a[i][j], " \n"[j + 1 == n]); + } + } + return 0; +} diff --git a/linear_algebra/adjugate_matrix/gen/anti55588_00.in b/linear_algebra/adjugate_matrix/gen/anti55588_00.in new file mode 100644 index 000000000..f54f5c950 --- /dev/null +++ b/linear_algebra/adjugate_matrix/gen/anti55588_00.in @@ -0,0 +1,4 @@ +3 +1 2 3 +0 0 1 +0 1 0 diff --git a/linear_algebra/adjugate_matrix/gen/example_00.in b/linear_algebra/adjugate_matrix/gen/example_00.in new file mode 100644 index 000000000..07a69e442 --- /dev/null +++ b/linear_algebra/adjugate_matrix/gen/example_00.in @@ -0,0 +1,4 @@ +3 +3 1 4 +1 5 9 +2 6 5 diff --git a/linear_algebra/adjugate_matrix/gen/example_01.in b/linear_algebra/adjugate_matrix/gen/example_01.in new file mode 100644 index 000000000..c767933a3 --- /dev/null +++ b/linear_algebra/adjugate_matrix/gen/example_01.in @@ -0,0 +1,4 @@ +3 +1 2 3 +4 5 6 +7 8 9 diff --git a/linear_algebra/adjugate_matrix/gen/example_02.in b/linear_algebra/adjugate_matrix/gen/example_02.in new file mode 100644 index 000000000..d5588077b --- /dev/null +++ b/linear_algebra/adjugate_matrix/gen/example_02.in @@ -0,0 +1,3 @@ +2 +0 1 +1 0 diff --git a/linear_algebra/adjugate_matrix/gen/highrank_max_random.cpp b/linear_algebra/adjugate_matrix/gen/highrank_max_random.cpp new file mode 100644 index 000000000..15a9b9a86 --- /dev/null +++ b/linear_algebra/adjugate_matrix/gen/highrank_max_random.cpp @@ -0,0 +1,49 @@ +#include +#include "random.h" +#include "../params.h" + +using namespace std; + +int main(int, char* argv[]) { + + + long long seed = atoll(argv[1]); + auto gen = Random(seed); + + int n = N_MAX; + vector> a(n, vector(n)); + for (int i = 0; i < n; i++) { + for (int j = 0; j < n; j++) { + a[i][j] = gen.uniform(0, MOD - 1); + } + } + + if(gen.uniform01()) { // create a linear dependency in rows + int i = gen.uniform(0, n - 1); + int j = gen.uniform(0, n - 1); + int k = gen.uniform(0, n - 1); + auto A = gen.uniform(0, MOD - 1); + auto B = gen.uniform(0, MOD - 1); + for(int l = 0; l < n; l++) { + a[i][l] = (A * a[j][l] + B * a[k][l]) % MOD; + } + } + if(gen.uniform01()) { // create a linear dependency in columns + int i = gen.uniform(0, n - 1); + int j = gen.uniform(0, n - 1); + int k = gen.uniform(0, n - 1); + auto A = gen.uniform(0, MOD - 1); + auto B = gen.uniform(0, MOD - 1); + for(int l = 0; l < n; l++) { + a[l][i] = (A * a[l][j] + B * a[l][k]) % MOD; + } + } + + printf("%d\n", n); + for (int i = 0; i < n; i++) { + for (int j = 0; j < n; j++) { + printf("%d%c", a[i][j], " \n"[j + 1 == n]); + } + } + return 0; +} diff --git a/linear_algebra/adjugate_matrix/gen/lowrank_max_random.cpp b/linear_algebra/adjugate_matrix/gen/lowrank_max_random.cpp new file mode 100644 index 000000000..c7d0b5792 --- /dev/null +++ b/linear_algebra/adjugate_matrix/gen/lowrank_max_random.cpp @@ -0,0 +1,60 @@ +#include +#include "random.h" +#include "../params.h" + +using namespace std; + +using ll = long long; + +int main(int, char* argv[]) { + + + long long seed = atoll(argv[1]); + auto gen = Random(seed); + + int n = gen.uniform(N_MAX - 10, N_MAX); + int rank = gen.uniform(1, n - 1); + + vector> a(n, vector(n)); + for (int i = 0; i < rank; i++) { + a[i][i] = gen.uniform(1LL, MOD - 1); + for (int j = i + 1; j < n; j++) { + a[i][j] = gen.uniform(0LL, MOD - 1); + } + } + for (int ph = 0; ph < 10000; ph++) { + int x = gen.uniform(0, n - 1); + int y = gen.uniform(0, n - 1); + ll freq = gen.uniform(1LL, MOD - 1); + if (x == y) continue; + if (gen.uniform_bool()) { + for (int i = 0; i < n; i++) { + a[x][i] += freq * a[y][i]; + a[x][i] %= MOD; + } + } else { + for (int i = 0; i < n; i++) { + a[i][x] += freq * a[i][y]; + a[i][x] %= MOD; + } + } + } + + gen.shuffle(a.begin(), a.end()); + for (int i = 0; i < n; i++) { + for (int j = i + 1; j < n; j++) { + swap(a[i][j], a[j][i]); + } + } + gen.shuffle(a.begin(), a.end()); + + printf("%d\n", n); + for (int i = 0; i < n; i++) { + for (int j = 0; j < n; j++) { + printf("%lld", a[i][j]); + if (j + 1 != n) printf(" "); + } + printf("\n"); + } + return 0; +} diff --git a/linear_algebra/adjugate_matrix/gen/max_random.cpp b/linear_algebra/adjugate_matrix/gen/max_random.cpp new file mode 100644 index 000000000..5e3699054 --- /dev/null +++ b/linear_algebra/adjugate_matrix/gen/max_random.cpp @@ -0,0 +1,30 @@ +#include +#include "random.h" +#include "../params.h" + +using namespace std; + +int main(int, char* argv[]) { + + + long long seed = atoll(argv[1]); + auto gen = Random(seed); + + int n = N_MAX; + vector> a(n, vector(n)); + for (int i = 0; i < n; i++) { + for (int j = 0; j < n; j++) { + a[i][j] = gen.uniform(0, MOD - 1); + } + } + + printf("%d\n", n); + for (int i = 0; i < n; i++) { + for (int j = 0; j < n; j++) { + printf("%d", a[i][j]); + if (j + 1 != n) printf(" "); + } + printf("\n"); + } + return 0; +} diff --git a/linear_algebra/adjugate_matrix/gen/perm_max_random.cpp b/linear_algebra/adjugate_matrix/gen/perm_max_random.cpp new file mode 100644 index 000000000..132ad0288 --- /dev/null +++ b/linear_algebra/adjugate_matrix/gen/perm_max_random.cpp @@ -0,0 +1,26 @@ +#include +#include "random.h" +#include "../params.h" + +using namespace std; + +int main(int, char* argv[]) { + + + long long seed = atoll(argv[1]); + auto gen = Random(seed); + + int n = gen.uniform(N_MAX - 10, N_MAX); + vector> a(n, vector(n)); + vector p = gen.perm(n); + for (int i = 0; i < n; i++) { + a[i][p[i]] = gen.uniform(0, MOD - 1); + } + printf("%d\n", n); + for (int i = 0; i < n; i++) { + for (int j = 0; j < n; j++) { + printf("%d%c", a[i][j], " \n"[j + 1 == n]); + } + } + return 0; +} diff --git a/linear_algebra/adjugate_matrix/gen/random.cpp b/linear_algebra/adjugate_matrix/gen/random.cpp new file mode 100644 index 000000000..1e06974bb --- /dev/null +++ b/linear_algebra/adjugate_matrix/gen/random.cpp @@ -0,0 +1,30 @@ +#include +#include "random.h" +#include "../params.h" + +using namespace std; + +int main(int, char* argv[]) { + + + long long seed = atoll(argv[1]); + auto gen = Random(seed); + + int n = gen.uniform(1, N_MAX); + vector> a(n, vector(n)); + for (int i = 0; i < n; i++) { + for (int j = 0; j < n; j++) { + a[i][j] = gen.uniform(0, MOD - 1); + } + } + + printf("%d\n", n); + for (int i = 0; i < n; i++) { + for (int j = 0; j < n; j++) { + printf("%d", a[i][j]); + if (j + 1 != n) printf(" "); + } + printf("\n"); + } + return 0; +} diff --git a/linear_algebra/adjugate_matrix/gen/signed_overflow.cpp b/linear_algebra/adjugate_matrix/gen/signed_overflow.cpp new file mode 100644 index 000000000..f2b275e73 --- /dev/null +++ b/linear_algebra/adjugate_matrix/gen/signed_overflow.cpp @@ -0,0 +1,27 @@ +#include +#include +#include + +#include "random.h" +#include "../params.h" + +using namespace std; + +int main() { + int val = MOD/2 - 1; + unsigned long long max_ll = numeric_limits::max(); + + // Find smallest size n where n * val * val > max_ll + int n = 0; + for (unsigned long long res = 0; res <= max_ll; res += (long long) val * val, ++n); + + cout << n << '\n'; + + for (int i = 0; i < n; ++i) { + for (int j = 0; j < n; ++j) { + cout << val << ((j == n - 1) ? '\n' : ' '); + } + } + + return 0; +} diff --git a/linear_algebra/adjugate_matrix/gen/unsigned_overflow.cpp b/linear_algebra/adjugate_matrix/gen/unsigned_overflow.cpp new file mode 100644 index 000000000..22002a3f5 --- /dev/null +++ b/linear_algebra/adjugate_matrix/gen/unsigned_overflow.cpp @@ -0,0 +1,32 @@ +#include +#include +#include + +#include "random.h" +#include "../params.h" + +using namespace std; + +int main() { + int val = MOD - 2; + + // Find smallest size n where n * val * val > numeric_limits::max() + int n = 0; + unsigned long long res = 0; + long long val2 = (long long) val * val; + while (res + val2 >= res) // Check if adding val2 to res will overflow + { + res += val2; + ++n; + } + + cout << n << '\n'; + + for (int i = 0; i < n; ++i) { + for (int j = 0; j < n; ++j) { + cout << val << ((j == n - 1) ? '\n' : ' '); + } + } + + return 0; +} diff --git a/linear_algebra/adjugate_matrix/hash.json b/linear_algebra/adjugate_matrix/hash.json new file mode 100644 index 000000000..edda0f222 --- /dev/null +++ b/linear_algebra/adjugate_matrix/hash.json @@ -0,0 +1,68 @@ +{ + "almost_identity_00.in": "518a2d94794f66c87a3c47235818d9728b0f7a517ab785d4e09a54f5ea983253", + "almost_identity_00.out": "55f50a484eb114b731ef51a7b344d050f23ee056f51b018031011f7f06f6cb73", + "almost_perm_max_random_00.in": "8aa6b4a453cdde0a554c4a901c4cdf61c5c5e5ca9ddb217d2725f1348a59376b", + "almost_perm_max_random_00.out": "0070f759caa8b4e674fc9040f0ff6509c66fdeadb06fdde1803f33d98d3aba5d", + "almost_perm_max_random_01.in": "82a8459ddbc6ebfdf7f763125c09961058d19b5473cb36b65d77fa6dee0276b5", + "almost_perm_max_random_01.out": "98bc5ccd7fb767ef9eb7cf3b9b64bb11bc25f468edf89f9c503d457206787291", + "almost_perm_max_random_02.in": "427fbd98ee1a59ceea40f03899bc4fdea9db69e4b9a9d4c69bf4d9bfc5c4365c", + "almost_perm_max_random_02.out": "5e1f27371d97f710c676546c16c8ee5c0a254984ef5bf1c73457b1db78ddd461", + "anti55588_00.in": "2e8cf4b2477fb8b91a4b455c92fe7c58b63464cdf5a68d687a37f3eb1234ff33", + "anti55588_00.out": "28b0e8bc3cab691b96106e8a4885488beea1eb4b95cda0d2bd8552b91460344f", + "example_00.in": "76560ae1361aca72022e81b37f015c5a35dce76e31f4ff4f2f0f34015734665e", + "example_00.out": "9d5f9095a59d5f8b17c3e95aa7f5b3370ea8a6bea333af6daa858ff4c80d4eed", + "example_01.in": "6a51e67c975c3659509b7fc9025eb09e243c99cf5a77a4567bb4cdc8636d49e4", + "example_01.out": "b248971c120a424409e916c1b85859a311b4fde6bda71081283d0bbae683ffb9", + "example_02.in": "39c4e6c347a3a8b171eb668ec5593e70219f84c4d57f852b2f603ecdc9c14cac", + "example_02.out": "cfde28ca2cd241f62a6db146e46bc8861a7adf63b503a3315f1e62127943cfbc", + "highrank_max_random_00.in": "2966feb99b12cbe66390efa1ec90e48137779e4baac46d819c796ef4867fee05", + "highrank_max_random_00.out": "8441114b97860fde2e84b9e5f3d76c421f4f4375cc3280459bd3ef96c593f0bb", + "highrank_max_random_01.in": "8f9f9b1553066a83faffdf308a14e739b2144536096905cde01e0a58dbc0265d", + "highrank_max_random_01.out": "1a3f433741e43ceaaf9c9d8bf9b9a0190020984ad48d56d2a0ca50487a9f470b", + "highrank_max_random_02.in": "b0f0ddd2a8fc533b4e9fa70147af1389c7456c0c3e27b6bfea45edc67a08ec7a", + "highrank_max_random_02.out": "a8d7b6d64287b3497e7c7118292ff9616eee484956b298ca17bf17dfac84e382", + "highrank_max_random_03.in": "9983e3e88c28dd60659d70ffd445c3705ae12dc20cf1bfd17fdf293f48cc0820", + "highrank_max_random_03.out": "9fa4a02c21fc9af27610d6dff7380871aaf682b000ffe2ef4a8902133a3052af", + "highrank_max_random_04.in": "afd9983d9ac940c873a5d74b700365bd1184c850e3211857f31f57b0eaf6a2e2", + "highrank_max_random_04.out": "0171d5ef31a50102e1a90d721d84c5ee171f98923d6459a6e0ed06aefe203395", + "lowrank_max_random_00.in": "dc6885b38af85e537531b438c8eece0f7e87850a2a49eba4b3810f5ac2d1e05c", + "lowrank_max_random_00.out": "46e5a66da8c3021e2f69d315c6a4f3c206d2d0e232f64a6bda4e6298ec7a44c2", + "lowrank_max_random_01.in": "e222ccdb01a746675cc6f4658b288d1deb3c3359235defc44f4fcf28b111064c", + "lowrank_max_random_01.out": "58c1c6531e046fb6535787cea9a35eeff8603ac766fa81b3fcb98a2295744b1a", + "lowrank_max_random_02.in": "c50006179417997b2109f75364c7ef578cbb881a2563821929e6b8f89237a287", + "lowrank_max_random_02.out": "be2cbd9a57a268337e7d5233062afbabe98cdab17cebff42b89ce393eae62509", + "lowrank_max_random_03.in": "dab9ba2517d6c6659e585eaf74f4c6aa003c51480956ac107314ece7954d55ea", + "lowrank_max_random_03.out": "bc27465decfd6e90c6f448ba51e8d7308bace7aa88908730b4ee877929c861e0", + "lowrank_max_random_04.in": "bf443bbc5c94446fb9988948dd372b0105c70c34ba6cae37fe0aa35ccf2ddf8d", + "lowrank_max_random_04.out": "2f6e38585fa5cf4c48f2ff73da2e8c2cadbd25b82e25075dd8c03eca3ff40b8c", + "max_random_00.in": "50d8b0042774c39e52fb1ce2086df9cecafe4ae808265921f266d88108c87e2d", + "max_random_00.out": "52dc6dc96a52673cb739be67c2b46f32111903d0a26f56c3a448df5ded96a963", + "max_random_01.in": "53eb5959cfe3d5f79807d253a03778c384f613b9fb078f0a8f2848aa16a54825", + "max_random_01.out": "bb990bdc61f4715d923969944d3cbc04c038e0138399f1fcb16448be419d0291", + "max_random_02.in": "9e7064b57e3fea776dc337a51d6926cffd4c0163b54f72234b59a11fc7f3c029", + "max_random_02.out": "bc2b1deac25fa17318aa54b25f576399b654e74625fb9aa6f38c6d1d673156f8", + "max_random_03.in": "1757b0dc5bd691f49a09e258739b283abac6854297633a32b2ee7291e4e102a1", + "max_random_03.out": "ee8543c3fe52ef311c4658bdce036b5eb2e83c3459a2f828995ff56ad3c7ba6b", + "max_random_04.in": "5385a7d0483888253b783f6ffb3195c78eefa72cf74d5f61b46aae7d29698105", + "max_random_04.out": "b17cafa8433e8a8d04c86dbf6989cd3e0a741ff528eb91089dc6e869927e6698", + "perm_max_random_00.in": "6c2fa92feaf606e0375a67ae0e308457c8a9c555230aac23ed9d1d118660b27f", + "perm_max_random_00.out": "a089546471db69ddca07f3b218258c2d2a80515a46d8acbef27bb0c367035d0a", + "perm_max_random_01.in": "1b8888b51057cc1f142f5d5a94c66fba85c38d5fdcc8590ce3fd9247292c8e62", + "perm_max_random_01.out": "f6dd5e689ba1827478fb1b2de7df3b53f2c916b53d162d3fb242b21ceb7eb942", + "perm_max_random_02.in": "aa8a6c7f2c233c7afbb3510094e4852dedd979ce913c43b31368f1711bfa0699", + "perm_max_random_02.out": "ac22012ead71be9c4f1716aee44bd9d02a517e9c66b13f58306d55f7a1730948", + "random_00.in": "2f3e29cefd7aecb6932be94ae495a8d3fa1acda143637a0a5259c2a47f7db875", + "random_00.out": "cee86c45cb73189379c5d08d34b4eeab1d23b160bc9bec09b8c69627b6cdaecb", + "random_01.in": "1d663fd396c4afe25556253ac2ffa73f88d8e245bd519219a15d1771668e938c", + "random_01.out": "f5617daf6c6bdf9d541d0e2b2ae4638401e9efdb93efb63fe85c994f510cc91f", + "random_02.in": "dba1df79ff80e4ac94cea6f13c7331aa58876d6c2d3691a8c2e287c12c742a5b", + "random_02.out": "9d0f45588b3bc334e2624fcb0db915c14ae109758514b4a8c65f952c64eb3245", + "random_03.in": "65da182beb1d893d5075e13c7ea4eaaeee0b6f4f08c2b3b10dd2c91c0d7feace", + "random_03.out": "e595e582a874843851cb15a8a7ef11476bca772c27b20fe6b55d34bf65010893", + "random_04.in": "be5de7ee3630de1e65d3a236644db57e5eafe50479d1a382128ea2bbc9120ac2", + "random_04.out": "74256963ff68f44ad3c3c64aad5a872ed1711b9925b84ad3eceebd656798b6d4", + "signed_overflow_00.in": "31b80c2aff345d32d117c940ec47f05fe808f34be0ca283d50df622ff899c00d", + "signed_overflow_00.out": "0efcec10f5c15d22c7d696e30330f519b7026bc600eb4f8f85b8101c8a8093e6", + "unsigned_overflow_00.in": "dfd8be53e4f5ae91e215e99136632ea635c710a6e029a296b3faa5a4fd1edfdb", + "unsigned_overflow_00.out": "b42106d99c73c3f503db0e4506af4aa184c9fe4fcde01eddd9352ef8ead2c3fe" +} \ No newline at end of file diff --git a/linear_algebra/adjugate_matrix/info.toml b/linear_algebra/adjugate_matrix/info.toml new file mode 100644 index 000000000..b9b07fc37 --- /dev/null +++ b/linear_algebra/adjugate_matrix/info.toml @@ -0,0 +1,42 @@ +title = 'Adjugate Matrix' +timelimit = 5.0 +forum = "https://github.com/yosupo06/library-checker-problems/issues/1269" + +[[tests]] + name = "example.in" + number = 3 +[[tests]] + name = "random.cpp" + number = 5 +[[tests]] + name = "max_random.cpp" + number = 5 +[[tests]] + name = "lowrank_max_random.cpp" + number = 5 +[[tests]] + name = "highrank_max_random.cpp" + number = 5 +[[tests]] + name = "perm_max_random.cpp" + number = 3 +[[tests]] + name = "almost_perm_max_random.cpp" + number = 3 +[[tests]] + name = "almost_identity.cpp" + number = 1 +[[tests]] + name = "anti55588.in" + number = 1 +[[tests]] + name = "signed_overflow.cpp" + number = 1 +[[tests]] + name = "unsigned_overflow.cpp" + number = 1 + +[params] + N_MAX = 500 + MOD = 998244353 + CXXFLAGS = "-std=c++23" diff --git a/linear_algebra/adjugate_matrix/sol/correct.cpp b/linear_algebra/adjugate_matrix/sol/correct.cpp new file mode 100644 index 000000000..1cd753dd6 --- /dev/null +++ b/linear_algebra/adjugate_matrix/sol/correct.cpp @@ -0,0 +1,362 @@ +// Author: Dmytro Fedoriaka + +#include +#include +#include +#include +#include +#include +#include +#include + +struct Random { + private: + // Use xoshiro256** + // References: http://xoshiro.di.unimi.it/xoshiro256starstar.c + static uint64_t rotl(const uint64_t x, int k) { + return (x << k) | (x >> (64 - k)); + } + + std::array s; + + uint64_t next() { + const uint64_t result_starstar = rotl(s[1] * 5, 7) * 9; + + const uint64_t t = s[1] << 17; + + s[2] ^= s[0]; + s[3] ^= s[1]; + s[1] ^= s[2]; + s[0] ^= s[3]; + + s[2] ^= t; + + s[3] = rotl(s[3], 45); + + return result_starstar; + } + + // random choice from [0, upper] + uint64_t next(uint64_t upper) { + if (!(upper & (upper + 1))) { + // b = 00..0011..11 + return next() & upper; + } + int lg = 63 - __builtin_clzll(upper); + uint64_t mask = (lg == 63) ? ~0ULL : (1ULL << (lg + 1)) - 1; + while (true) { + uint64_t r = next() & mask; + if (r <= upper) + return r; + } + } + + public: + Random(uint64_t seed = 0) { + // Use splitmix64 + // Reference: http://xoshiro.di.unimi.it/splitmix64.c + for (int i = 0; i < 4; i++) { + uint64_t z = (seed += 0x9e3779b97f4a7c15); + z = (z ^ (z >> 30)) * 0xbf58476d1ce4e5b9; + z = (z ^ (z >> 27)) * 0x94d049bb133111eb; + s[i] = z ^ (z >> 31); + } + } + + // random choice from [lower, upper] + template + T uniform(T lower, T upper) { + assert(lower <= upper); + return T(lower + next(uint64_t(upper - lower))); + } + + // random choice from false or true + bool uniform_bool() { return uniform(0, 1) == 1; } + + // random choice from [0.0, 1.0] + double uniform01() { + uint64_t v = next(1ULL << 63); + return double(v) / (1ULL << 63); + } + + // random choice non-empty sub-interval from interval [lower, upper) + // equal: random choice 2 disjoint elements from [lower, upper] + template + std::pair uniform_pair(T lower, T upper) { + assert(upper - lower >= 1); + T a, b; + do { + a = uniform(lower, upper); + b = uniform(lower, upper); + } while (a == b); + if (a > b) std::swap(a, b); + return {a, b}; + } + + // generate random lower string that length = n + std::string lower_string(size_t n) { + std::string res = ""; + for (size_t i = 0; i < n; i++) { + res += uniform('a', 'z'); + } + return res; + } + + // random shuffle + template + void shuffle(Iter first, Iter last) { + if (first == last) return; + // Reference and edit: + // cpprefjp - C++日本語リファレンス + // (https://cpprefjp.github.io/reference/algorithm/shuffle.html) + int len = 1; + for (auto it = first + 1; it != last; it++) { + len++; + int j = uniform(0, len - 1); + if (j != len - 1) + iter_swap(it, first + j); + } + } + + // generate random permutation that length = n + template + std::vector perm(size_t n) { + std::vector idx(n); + std::iota(idx.begin(), idx.end(), T(0)); + shuffle(idx.begin(), idx.end()); + return idx; + } + + // random choise n elements from [lower, upper] + template + std::vector choice(size_t n, T lower, T upper) { + assert(T(n) <= upper - lower + 1); + std::set res; + while (res.size() < n) res.insert(uniform(lower, upper)); + return {res.begin(), res.end()}; + } +} global_gen; + +using namespace std; + +int64_t MOD = 998244353; +struct IntMod { + int64_t v; + IntMod() : v(0) {} + IntMod(int64_t v_) : v(v_) {if((uint64_t)v>=(uint64_t)MOD){v%=MOD;if(v<0)v+=MOD;}} + inline IntMod operator + (const IntMod& y) const {IntMod a(*this); a+=y; return a;} + inline IntMod operator - (const IntMod& y) const {IntMod a(*this); a-=y; return a;} + inline IntMod operator * (const IntMod& y) const {return {v*y.v};} + inline IntMod pow(int64_t y) const {IntMod a(1),m(v);while(y!=0){if(y&1){a=a*m;}m=m*m;y>>=1;}return a;} + inline IntMod inverse() const { + int64_t g=MOD,r=v,x=0,y=1; + while(r!=0){int64_t q=g/r;g%=r;swap(g,r);x-=q*y;swap(x,y);} + return IntMod(x+(x<0)*MOD); + } + bool operator == (const IntMod& y) const {return v==y.v;} + bool operator != (const IntMod& y) const {return v!=y.v;} + inline void operator += (const IntMod& y) {(v+=y.v)>=MOD && (v-=MOD);} + inline void operator -= (const IntMod& y) {(v-=y.v)<0 && (v+=MOD);} + inline void operator *= (const IntMod& y) {v*=y.v; v%=MOD;} +}; +inline IntMod operator / (const IntMod& x, const IntMod& y) {return x * y.inverse();} + +template +class SquareMatrix { + public: + SquareMatrix(size_t n) : n_(n) { data_.resize(n * n); } + static SquareMatrix Read() { + size_t n; + scanf("%zu", &n); + SquareMatrix ans(n); + for (size_t i = 0; i < n * n; ++i) scanf("%" SCNd64, &ans.data_[i].v); + return ans; + } + static SquareMatrix MakeZeroMatrix(size_t n) { + SquareMatrix ans(n); + ans.data_.assign(n * n, 0); + return ans; + } + + SquareMatrix AdjointToMinors() const { + SquareMatrix ans(n_); + for (size_t i = 0; i < n_; i++) { + for (size_t j = 0; j < n_; j++) { + T val = Get(j, i); + if ((i + j) % 2 == 1) val *= -1; + ans.Set(i, j, val); + } + } + return ans; + } + + void MulByScalar(T k) { + for (size_t i = 0; i < n_ * n_; ++i) data_[i] *= k; + } + + void Print() const { + for (size_t i = 0; i < n_; i++) { + for (size_t j = 0; j < n_; j++) { + printf("%" SCNd64 "%c", data_[i * n_ + j].v, " \n"[j + 1 == n_]); + } + } + } + + int GetN() const { return n_; } + T Get(int i, int j) const { return data_[i * n_ + j]; } + void Set(int i, int j, T value) { data_[i * n_ + j] = value; } + + private: + size_t n_; + vector data_; +}; + +class GaussEliminator { + public: + // For non-degenrate matrix, finds determinant and inverse. + // For degenerate matrix, finds rank. + void Run(const SquareMatrix& mx) { + int n = mx.GetN(); + n_ = n; + row_size_ = 2 * n; + + rows_.assign(n, vector(2 * n, 0)); + for (int i = 0; i < n; i++) { + for (int j = 0; j < n; j++) rows_[i][j] = mx.Get(i, j).v; + rows_[i][n + i] = 1; + } + det_inv_ = 1; + + // Forward pass. + int row_idx = 0; + for (int col_idx = 0; col_idx < n; col_idx++) { + if (rows_[row_idx][col_idx] == 0) { + int row_to_swap = -1; + for (int j = row_idx + 1; j < n_; j++) { + if (rows_[j][col_idx] != 0) { + row_to_swap = j; + break; + } + } + if (row_to_swap == -1) { + // Matrix is degenerate, but carry on because we want to know rank. + continue; + } + SwapRows(row_idx, row_to_swap); + } + + MulRowBy(row_idx, IntMod(rows_[row_idx][col_idx]).inverse().v); + for (int j = row_idx + 1; j < n; j++) { + AddRows(j, row_idx, -rows_[j][col_idx]); + } + row_idx++; + } + + // Check if matrix is degenarate, in which case only compute rank. + rank_ = row_idx; + if (rank_ != n) { + assert(rank_ < n); + return; + } + + // Backward pass. + for (int i = n - 1; i > 0; i--) { + for (int j = i - 1; j >= 0; j--) { + AddRows(j, i, -rows_[j][i]); + } + } + } + + SquareMatrix GetInverse() { + assert(rank_ == n_); + SquareMatrix ans(n_); + for (int i = 0; i < n_; i++) { + for (int j = 0; j < n_; j++) { + ans.Set(i, j, IntMod(rows_[i][n_ + j])); + } + } + return ans; + } + + IntMod GetDeterminant() { + return rank_ == n_ ? IntMod(det_inv_).inverse() : IntMod(0); + } + + int GetRank() { return rank_; } + + private: + // rows[i1] += k*rows[i2] + void AddRows(size_t i1, size_t i2, int64_t k) { + // assert(i1 != i2); + if (k == 0) return; + int64_t* ptr1 = &(rows_[i1][0]); + int64_t* ptr1_end = ptr1 + row_size_; + const int64_t* ptr2 = &(rows_[i2][0]); + while (ptr1 != ptr1_end) { + *ptr1 = (*ptr1 + k * (*ptr2)) % MOD; + ptr1++; + ptr2++; + } + } + + void SwapRows(size_t i1, size_t i2) { + // assert(i1 != i2); + det_inv_ *= -1; + swap(rows_[i1], rows_[i2]); + } + + void MulRowBy(int i, int64_t k) { + assert(k != 0); + det_inv_ = (det_inv_ * k) % MOD; + int64_t* ptr1 = &(rows_[i][0]); + int64_t* ptr1_end = ptr1 + row_size_; + while (ptr1 != ptr1_end) { + *ptr1 = (*ptr1 * k) % MOD; + ptr1++; + } + } + + vector> rows_; + int64_t det_inv_; + int rank_ = -1; + int n_, row_size_; +}; + +SquareMatrix GetAdjoint(const SquareMatrix& A) { + int n = A.GetN(); + GaussEliminator ge; + + SquareMatrix A_ext(n + 1); + for (int i = 0; i < n; i++) { + for (int j = 0; j < n; j++) { + A_ext.Set(i, j, A.Get(i, j)); + } + } + for (int i = 0; i < n + 1; i++) { + A_ext.Set(n, i, IntMod(global_gen.uniform(0, MOD - 1))); + A_ext.Set(i, n, IntMod(global_gen.uniform(0, MOD - 1))); + } + ge.Run(A_ext); + if (ge.GetRank() != n + 1) { + return SquareMatrix::MakeZeroMatrix(n); + } + + SquareMatrix A2 = ge.GetInverse(); // A_ext^-1. + IntMod x_hat = A2.Get(n, n); + SquareMatrix ans(n); + for (int i = 0; i < n; i++) { + for (int j = 0; j < n; j++) { + ans.Set(i, j, x_hat * A2.Get(i, j) - A2.Get(i, n) * A2.Get(n, j)); + } + } + ans.MulByScalar(ge.GetDeterminant()); + return ans; +} + +int32_t main() { + SquareMatrix A = SquareMatrix::Read(); + SquareMatrix M = GetAdjoint(A); + M.Print(); + + return 0; +} diff --git a/linear_algebra/adjugate_matrix/task.md b/linear_algebra/adjugate_matrix/task.md new file mode 100644 index 000000000..62be0ae01 --- /dev/null +++ b/linear_algebra/adjugate_matrix/task.md @@ -0,0 +1,49 @@ +## @{keyword.statement} + +@{lang.en} +Given $N \times N$ matrix $A = \lbrace a_{ij} \rbrace$ with entries in $\mathbb{Z}/@{param.MOD}\mathbb{Z}$, print $\operatorname{adj} A = \lbrace (-1)^{i+j}M_{ji} \rbrace$, where $M_{ij}$ is the determinant of the matrix that is obtained from $A$ by removing its $i$-th row and $j$-th column. +@{lang.ja} + +@{lang.end} + +## @{keyword.constraints} + +- $1 \leq N \leq @{param.N_MAX}$ +- $0 \leq a_{ij} < @{param.MOD}$ + +## @{keyword.input} + +``` +$N$ +$a_{11}$ $a_{12}$ ... $a_{1N}$ +$a_{21}$ $a_{22}$ ... $a_{2N}$ +: +$a_{N1}$ $a_{N2}$ ... $a_{NN}$ +``` + +## @{keyword.output} + +@{lang.en} +Print $b_{ij} = (-1)^{i+j} M_{ji}$: +@{lang.ja} + +@{lang.end} + +``` +$b_{11}$ $b_{12}$ ... $b_{1N}$ +$b_{21}$ $b_{22}$ ... $b_{2N}$ +: +$b_{N1}$ $b_{N2}$ ... $b_{NN}$ +``` + +@{lang.ja} + +@{lang.end} + +## @{keyword.sample} + +@{example.example_00} + +@{example.example_01} + +@{example.example_02} diff --git a/linear_algebra/adjugate_matrix/verifier.cpp b/linear_algebra/adjugate_matrix/verifier.cpp new file mode 100644 index 000000000..fd090f07e --- /dev/null +++ b/linear_algebra/adjugate_matrix/verifier.cpp @@ -0,0 +1,20 @@ +#include + +#include "testlib.h" +#include "params.h" + +int main() { + registerValidation(); + + int n = inf.readInt(1, N_MAX); + inf.readChar('\n'); + for (int i = 0; i < n; i++) { + for (int j = 0; j < n; j++) { + inf.readInt(0, MOD - 1); + if (j + 1 != n) inf.readSpace(); + } + inf.readChar('\n'); + } + inf.readEof(); + return 0; +} From fcfb05ec1d773385a628def904fa71c1c810275e Mon Sep 17 00:00:00 2001 From: Oleksandr Kulkov Date: Mon, 28 Oct 2024 12:04:31 +0100 Subject: [PATCH 2/5] japanese statement --- linear_algebra/adjugate_matrix/task.md | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/linear_algebra/adjugate_matrix/task.md b/linear_algebra/adjugate_matrix/task.md index 62be0ae01..7652855ed 100644 --- a/linear_algebra/adjugate_matrix/task.md +++ b/linear_algebra/adjugate_matrix/task.md @@ -3,7 +3,8 @@ @{lang.en} Given $N \times N$ matrix $A = \lbrace a_{ij} \rbrace$ with entries in $\mathbb{Z}/@{param.MOD}\mathbb{Z}$, print $\operatorname{adj} A = \lbrace (-1)^{i+j}M_{ji} \rbrace$, where $M_{ij}$ is the determinant of the matrix that is obtained from $A$ by removing its $i$-th row and $j$-th column. @{lang.ja} - +$\mathbb{Z}/@{param.MOD}\mathbb{Z}$ 成分の $N\times N$ 行列 $A = \lbrace a_{ij} \rbrace$ が与えられます. +$A$ の余因子行列 $\operatorname{adj} A = \lbrace (-1)^{i+j}M_{ji} \rbrace$ を出力してください.ただし $M_{ij}$ は $A$ から $i$ 行目,$j$ 列目を取り除くことによって得られる行列の行列式です. @{lang.end} ## @{keyword.constraints} @@ -36,10 +37,6 @@ $b_{21}$ $b_{22}$ ... $b_{2N}$ $b_{N1}$ $b_{N2}$ ... $b_{NN}$ ``` -@{lang.ja} - -@{lang.end} - ## @{keyword.sample} @{example.example_00} From de20f413c6d17a1a022f9ce3e5af762b71d6ee14 Mon Sep 17 00:00:00 2001 From: Oleksandr Kulkov Date: Mon, 28 Oct 2024 12:09:25 +0100 Subject: [PATCH 3/5] Update linear_algebra/adjugate_matrix/task.md --- linear_algebra/adjugate_matrix/task.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/linear_algebra/adjugate_matrix/task.md b/linear_algebra/adjugate_matrix/task.md index 7652855ed..996e5a6ea 100644 --- a/linear_algebra/adjugate_matrix/task.md +++ b/linear_algebra/adjugate_matrix/task.md @@ -27,7 +27,7 @@ $a_{N1}$ $a_{N2}$ ... $a_{NN}$ @{lang.en} Print $b_{ij} = (-1)^{i+j} M_{ji}$: @{lang.ja} - +$b_{ij} = (-1)^{i+j} M_{ji}$ を出力してください : @{lang.end} ``` From 826262c3b208ce09f6c26e58da5e5ab9cdcac601 Mon Sep 17 00:00:00 2001 From: Oleksandr Kulkov Date: Mon, 28 Oct 2024 20:52:51 +0100 Subject: [PATCH 4/5] Add Frobenius form + n=1 --- .../adjugate_matrix/gen/example_03.in | 2 + .../gen/nontrivial_frobenius_form.cpp | 216 ++++++++++++++++++ linear_algebra/adjugate_matrix/hash.json | 22 ++ linear_algebra/adjugate_matrix/info.toml | 6 +- 4 files changed, 244 insertions(+), 2 deletions(-) create mode 100644 linear_algebra/adjugate_matrix/gen/example_03.in create mode 100644 linear_algebra/adjugate_matrix/gen/nontrivial_frobenius_form.cpp diff --git a/linear_algebra/adjugate_matrix/gen/example_03.in b/linear_algebra/adjugate_matrix/gen/example_03.in new file mode 100644 index 000000000..b261da18d --- /dev/null +++ b/linear_algebra/adjugate_matrix/gen/example_03.in @@ -0,0 +1,2 @@ +1 +0 diff --git a/linear_algebra/adjugate_matrix/gen/nontrivial_frobenius_form.cpp b/linear_algebra/adjugate_matrix/gen/nontrivial_frobenius_form.cpp new file mode 100644 index 000000000..d2a98ac4e --- /dev/null +++ b/linear_algebra/adjugate_matrix/gen/nontrivial_frobenius_form.cpp @@ -0,0 +1,216 @@ +#include +#include +#include +#include +#include "random.h" +#include "../params.h" + +using namespace std; + +using ll = long long; +using u32 = unsigned int; +using u64 = unsigned long long; + +template +using vc = vector; +template +using vvc = vector>; + +#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 +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 +vc> matrix_mul(const vc> &A, const vc> &B, int N1 = -1, int N2 = -1, int N3 = -1) { + if (N1 == -1) { N1 = len(A), N2 = len(B), N3 = len(B[0]); } + vvc b(N2, vc(N3)); + FOR(i, N2) FOR(j, N3) b[j][i] = B[i][j]; + vvc C(N1, vc(N3)); + FOR(n, N1) FOR(m, N2) FOR(k, N3) C[n][k] += A[n][m] * b[k][m]; + return C; +} + +// (det, invA) をかえす +template +pair>> matrix_inv(vc> A) { + T det = 1; + int N = len(A); + vvc B(N, vc(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> 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 random_poly(int n, Random &gen) { + vc f(n + 1); + f[n] = 1; + FOR(i, n) f[i] = gen.uniform(0, mint::get_mod() - 1); + return f; +} + +vvc gen_mat(vc S, Random &gen) { + sort(all(S)); + int B = len(S); + vvc poly(B); + poly[0] = random_poly(S[0], gen); + FOR(b, 1, B) { + vc f = poly[b - 1]; + vc g = random_poly(S[b] - S[b - 1], gen); + vc 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 A(N, vc(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 P(N, vc(N)); + FOR(i, N) FOR(j, N) P[i][j] = gen.uniform(0, mint::get_mod() - 1); + auto [det, IP] = matrix_inv(P); + if (det == mint(0)) continue; + A = matrix_mul(IP, A); + A = matrix_mul(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 S; + int now = 0; + while (now < N) { + int k = gen.uniform(1, K); + if (now + k > N) continue; + S.emplace_back(k), now += k; + } + vvc 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 cut = gen.choice(K - 1, 1, N - 1); + cut.insert(cut.begin(), 0); + cut.emplace_back(N); + assert(len(cut) == K + 1); + vc S(K); + FOR(i, K) S[i] = cut[i + 1] - cut[i]; + vvc A = gen_mat(S, gen); + out(N, A); + } + else { + assert(0); + } + return 0; +} diff --git a/linear_algebra/adjugate_matrix/hash.json b/linear_algebra/adjugate_matrix/hash.json index edda0f222..3ff44fb44 100644 --- a/linear_algebra/adjugate_matrix/hash.json +++ b/linear_algebra/adjugate_matrix/hash.json @@ -15,6 +15,8 @@ "example_01.out": "b248971c120a424409e916c1b85859a311b4fde6bda71081283d0bbae683ffb9", "example_02.in": "39c4e6c347a3a8b171eb668ec5593e70219f84c4d57f852b2f603ecdc9c14cac", "example_02.out": "cfde28ca2cd241f62a6db146e46bc8861a7adf63b503a3315f1e62127943cfbc", + "example_03.in": "5d90ef7fc0d040fd56a1e48697cfa99e0dfaf4fd803aefefc3b5053ec1d36aea", + "example_03.out": "4355a46b19d348dc2f57c046f8ef63d4538ebb936000f3c9ee954a27460dd865", "highrank_max_random_00.in": "2966feb99b12cbe66390efa1ec90e48137779e4baac46d819c796ef4867fee05", "highrank_max_random_00.out": "8441114b97860fde2e84b9e5f3d76c421f4f4375cc3280459bd3ef96c593f0bb", "highrank_max_random_01.in": "8f9f9b1553066a83faffdf308a14e739b2144536096905cde01e0a58dbc0265d", @@ -45,6 +47,26 @@ "max_random_03.out": "ee8543c3fe52ef311c4658bdce036b5eb2e83c3459a2f828995ff56ad3c7ba6b", "max_random_04.in": "5385a7d0483888253b783f6ffb3195c78eefa72cf74d5f61b46aae7d29698105", "max_random_04.out": "b17cafa8433e8a8d04c86dbf6989cd3e0a741ff528eb91089dc6e869927e6698", + "nontrivial_frobenius_form_00.in": "eae9b978d16e992fcc24a15832867c099fbc5f9f17fa071c9c7b7e6b7f877873", + "nontrivial_frobenius_form_00.out": "d12cc85ce1c45ac150c32a77464091af793ab24bc5a36dc50f281d1e239779f9", + "nontrivial_frobenius_form_01.in": "306a2fa13dd29ee02778336807752d1b192084edad79fe55b9038b7d3983ed1d", + "nontrivial_frobenius_form_01.out": "66b27fb56e2b1020b8e179283898efa7df3a38f4f52ca176a5fd9faf8d641c84", + "nontrivial_frobenius_form_02.in": "d996b0b13a10974c430c2db6b32878417c5e769b16a11000c87f993587a29cf0", + "nontrivial_frobenius_form_02.out": "ccb6ed21bd347c7e6750e8e7d082614c3d48169656583c3769dc06c530e269c8", + "nontrivial_frobenius_form_03.in": "2da9a3010ce15fbf21077d3ee02485df0aeb4f1ce9c08d590794197b46c4ab85", + "nontrivial_frobenius_form_03.out": "063c1cf763e2590f4391f343b5bb802d4555ff77384ab514f812c3f08c347b7d", + "nontrivial_frobenius_form_04.in": "5c3a5835f52f62a0e5a39ad820f77dd3a2895ea3fa3b8d9a280161e78808123e", + "nontrivial_frobenius_form_04.out": "2d8d23120c3b326243a7825aefd75fe45a840a5261a03fdc2e5035487ffd5c6b", + "nontrivial_frobenius_form_05.in": "70ae11941fb9eab5a7122d33f9a0c6cf6c3e8510b13c998136e82347a21f5cc7", + "nontrivial_frobenius_form_05.out": "6690aa84b7a2bc57d62e5e326c4128fc921104d7081b5a3e331fe6acb637b66b", + "nontrivial_frobenius_form_06.in": "47a825c4a3c28630770da597593e0e00e43eef54f52368433606282064b6a8a8", + "nontrivial_frobenius_form_06.out": "38aa48998ed0d399da81cf49dffb1c5e7b5db4e7aa3822398422313a01d0e76e", + "nontrivial_frobenius_form_07.in": "80ca6e0ff0a99e674573c5b85cfa02a444349c7232dd13068301102d73ab8314", + "nontrivial_frobenius_form_07.out": "1cbd3f1ea06402c42d56c0f07cd55a5eb04980cd6d3e8d22f7fb84f7a28c888b", + "nontrivial_frobenius_form_08.in": "7815ed6591321105c99262d0de8f50eb9f2d48444c2035967cfdfbfbf29c5a02", + "nontrivial_frobenius_form_08.out": "7f43b2113c02fab133ef042cd1160a1aa692f3fdd8f6e03a4c0393d43fd429f8", + "nontrivial_frobenius_form_09.in": "c5c9e32af2630ba239db00dda4da74ddeebaabf011397500a2bdf942c833a07a", + "nontrivial_frobenius_form_09.out": "e4b8e16d4d05284df47612ddae3b4553654bc16bbcf701b9e85d1af7b0e44349", "perm_max_random_00.in": "6c2fa92feaf606e0375a67ae0e308457c8a9c555230aac23ed9d1d118660b27f", "perm_max_random_00.out": "a089546471db69ddca07f3b218258c2d2a80515a46d8acbef27bb0c367035d0a", "perm_max_random_01.in": "1b8888b51057cc1f142f5d5a94c66fba85c38d5fdcc8590ce3fd9247292c8e62", diff --git a/linear_algebra/adjugate_matrix/info.toml b/linear_algebra/adjugate_matrix/info.toml index b9b07fc37..05b273abc 100644 --- a/linear_algebra/adjugate_matrix/info.toml +++ b/linear_algebra/adjugate_matrix/info.toml @@ -4,7 +4,7 @@ forum = "https://github.com/yosupo06/library-checker-problems/issues/1269" [[tests]] name = "example.in" - number = 3 + number = 4 [[tests]] name = "random.cpp" number = 5 @@ -35,8 +35,10 @@ forum = "https://github.com/yosupo06/library-checker-problems/issues/1269" [[tests]] name = "unsigned_overflow.cpp" number = 1 +[[tests]] + name = "nontrivial_frobenius_form.cpp" + number = 10 [params] N_MAX = 500 MOD = 998244353 - CXXFLAGS = "-std=c++23" From 0814e80845877675f7013b0c4a96dbeb202daf7b Mon Sep 17 00:00:00 2001 From: Oleksandr Kulkov Date: Mon, 28 Oct 2024 21:00:42 +0100 Subject: [PATCH 5/5] Update linear_algebra/adjugate_matrix/task.md Co-authored-by: maspypy <45988013+maspypy@users.noreply.github.com> --- linear_algebra/adjugate_matrix/task.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/linear_algebra/adjugate_matrix/task.md b/linear_algebra/adjugate_matrix/task.md index 996e5a6ea..a363dec1e 100644 --- a/linear_algebra/adjugate_matrix/task.md +++ b/linear_algebra/adjugate_matrix/task.md @@ -44,3 +44,5 @@ $b_{N1}$ $b_{N2}$ ... $b_{NN}$ @{example.example_01} @{example.example_02} + +@{example.example_03}