From 3f5ba067af4002959d576c7b0074f29a4ca66cfe Mon Sep 17 00:00:00 2001 From: maspypy Date: Sun, 5 Nov 2023 02:22:17 +0900 Subject: [PATCH 1/3] add problem --- math/pow_of_matrix/checker.cpp | 62 ++++ math/pow_of_matrix/gen/example_00.in | 3 + math/pow_of_matrix/gen/example_01.in | 4 + math/pow_of_matrix/gen/example_02.in | 4 + math/pow_of_matrix/gen/lowrank_max_random.cpp | 59 ++++ math/pow_of_matrix/gen/max_random.cpp | 33 ++ math/pow_of_matrix/gen/max_random_worst.cpp | 33 ++ math/pow_of_matrix/gen/perm_max_random.cpp | 31 ++ math/pow_of_matrix/gen/random.cpp | 33 ++ math/pow_of_matrix/gen/signed_overflow.cpp | 35 ++ math/pow_of_matrix/gen/small.cpp | 37 ++ math/pow_of_matrix/gen/unsigned_overflow.cpp | 39 +++ math/pow_of_matrix/hash.json | 66 ++++ math/pow_of_matrix/info.toml | 36 ++ math/pow_of_matrix/sol/correct.cpp | 317 ++++++++++++++++++ math/pow_of_matrix/task.md | 39 +++ math/pow_of_matrix/verifier.cpp | 22 ++ 17 files changed, 853 insertions(+) create mode 100644 math/pow_of_matrix/checker.cpp create mode 100644 math/pow_of_matrix/gen/example_00.in create mode 100644 math/pow_of_matrix/gen/example_01.in create mode 100644 math/pow_of_matrix/gen/example_02.in create mode 100644 math/pow_of_matrix/gen/lowrank_max_random.cpp create mode 100644 math/pow_of_matrix/gen/max_random.cpp create mode 100644 math/pow_of_matrix/gen/max_random_worst.cpp create mode 100644 math/pow_of_matrix/gen/perm_max_random.cpp create mode 100644 math/pow_of_matrix/gen/random.cpp create mode 100644 math/pow_of_matrix/gen/signed_overflow.cpp create mode 100644 math/pow_of_matrix/gen/small.cpp create mode 100644 math/pow_of_matrix/gen/unsigned_overflow.cpp create mode 100644 math/pow_of_matrix/hash.json create mode 100644 math/pow_of_matrix/info.toml create mode 100644 math/pow_of_matrix/sol/correct.cpp create mode 100644 math/pow_of_matrix/task.md create mode 100644 math/pow_of_matrix/verifier.cpp diff --git a/math/pow_of_matrix/checker.cpp b/math/pow_of_matrix/checker.cpp new file mode 100644 index 000000000..6a66d5330 --- /dev/null +++ b/math/pow_of_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/math/pow_of_matrix/gen/example_00.in b/math/pow_of_matrix/gen/example_00.in new file mode 100644 index 000000000..8223d21ce --- /dev/null +++ b/math/pow_of_matrix/gen/example_00.in @@ -0,0 +1,3 @@ +2 7 +0 1 +1 1 diff --git a/math/pow_of_matrix/gen/example_01.in b/math/pow_of_matrix/gen/example_01.in new file mode 100644 index 000000000..28cb328c1 --- /dev/null +++ b/math/pow_of_matrix/gen/example_01.in @@ -0,0 +1,4 @@ +3 0 +0 0 0 +0 0 0 +0 0 0 diff --git a/math/pow_of_matrix/gen/example_02.in b/math/pow_of_matrix/gen/example_02.in new file mode 100644 index 000000000..586769b06 --- /dev/null +++ b/math/pow_of_matrix/gen/example_02.in @@ -0,0 +1,4 @@ +3 1000000000000000000 +1 2 3 +4 5 6 +7 8 9 diff --git a/math/pow_of_matrix/gen/lowrank_max_random.cpp b/math/pow_of_matrix/gen/lowrank_max_random.cpp new file mode 100644 index 000000000..ad5cffc55 --- /dev/null +++ b/math/pow_of_matrix/gen/lowrank_max_random.cpp @@ -0,0 +1,59 @@ +#include +#include "random.h" +#include "../params.h" + +using namespace std; + +using ll = long long; + +void out(int n, ll K, vector> a) { + printf("%d %lld\n", n, K); + 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"); + } +} + +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()); + + ll K = gen.uniform(0, K_MAX); + out(n, K, a); + return 0; +} diff --git a/math/pow_of_matrix/gen/max_random.cpp b/math/pow_of_matrix/gen/max_random.cpp new file mode 100644 index 000000000..72bb494c8 --- /dev/null +++ b/math/pow_of_matrix/gen/max_random.cpp @@ -0,0 +1,33 @@ +#include +#include "random.h" +#include "../params.h" + +using namespace std; + +using ll = long long; + +void out(int n, ll K, vector> a) { + printf("%d %lld\n", n, K); + 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"); + } +} + +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); } + } + + ll K = gen.uniform(0, K_MAX); + out(n, K, a); + return 0; +} diff --git a/math/pow_of_matrix/gen/max_random_worst.cpp b/math/pow_of_matrix/gen/max_random_worst.cpp new file mode 100644 index 000000000..57d07de93 --- /dev/null +++ b/math/pow_of_matrix/gen/max_random_worst.cpp @@ -0,0 +1,33 @@ +#include +#include "random.h" +#include "../params.h" + +using namespace std; + +using ll = long long; + +void out(int n, ll K, vector> a) { + printf("%d %lld\n", n, K); + 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"); + } +} + +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); } + } + + ll K = (1LL << 59) - 1; + out(n, K, a); + return 0; +} diff --git a/math/pow_of_matrix/gen/perm_max_random.cpp b/math/pow_of_matrix/gen/perm_max_random.cpp new file mode 100644 index 000000000..281702ad5 --- /dev/null +++ b/math/pow_of_matrix/gen/perm_max_random.cpp @@ -0,0 +1,31 @@ +#include +#include "random.h" +#include "../params.h" + +using namespace std; +using ll = long long; + +void out(int n, ll K, vector> a) { + printf("%d %lld\n", n, K); + 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"); + } +} + +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); } + + ll K = gen.uniform(0, K_MAX); + out(n, K, a); + return 0; +} diff --git a/math/pow_of_matrix/gen/random.cpp b/math/pow_of_matrix/gen/random.cpp new file mode 100644 index 000000000..04ddcb86a --- /dev/null +++ b/math/pow_of_matrix/gen/random.cpp @@ -0,0 +1,33 @@ +#include +#include "random.h" +#include "../params.h" + +using namespace std; + +using ll = long long; + +void out(int n, ll K, vector> a) { + printf("%d %lld\n", n, K); + 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"); + } +} + +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); } + } + + ll K = gen.uniform(0, K_MAX); + out(n, K, a); + return 0; +} diff --git a/math/pow_of_matrix/gen/signed_overflow.cpp b/math/pow_of_matrix/gen/signed_overflow.cpp new file mode 100644 index 000000000..122b6fbf0 --- /dev/null +++ b/math/pow_of_matrix/gen/signed_overflow.cpp @@ -0,0 +1,35 @@ +#include +#include +#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 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) + ; + ll K = gen.uniform(0, K_MAX); + + printf("%d %lld\n", n, K); + + for (int i = 0; i < n; ++i) { + for (int j = 0; j < n; ++j) { + if (j) printf(" "); + printf("%d", val); + } + printf("\n"); + } + return 0; +} diff --git a/math/pow_of_matrix/gen/small.cpp b/math/pow_of_matrix/gen/small.cpp new file mode 100644 index 000000000..1e1cfa6bc --- /dev/null +++ b/math/pow_of_matrix/gen/small.cpp @@ -0,0 +1,37 @@ +#include +#include "random.h" +#include "../params.h" + +using namespace std; + +using ll = long long; + +void out(int n, ll K, vector> a) { + printf("%d %lld\n", n, K); + 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"); + } +} + +int main(int, char* argv[]) { + long long seed = atoll(argv[1]); + auto gen = Random(seed); + + vector ns = {1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3}; + vector ks = {0, 0, 0, 1, 1, 1, 2, 2, 2, 3, 3, 3}; + + int n = ns[seed % 12]; + int k = ks[seed % 12]; + + 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); } + } + + out(n, k, a); + return 0; +} diff --git a/math/pow_of_matrix/gen/unsigned_overflow.cpp b/math/pow_of_matrix/gen/unsigned_overflow.cpp new file mode 100644 index 000000000..67a6113cf --- /dev/null +++ b/math/pow_of_matrix/gen/unsigned_overflow.cpp @@ -0,0 +1,39 @@ +#include +#include +#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 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; + } + + ll K = gen.uniform(0, K_MAX); + printf("%d %lld\n", n, K); + + for (int i = 0; i < n; ++i) { + for (int j = 0; j < n; ++j) { + if (j) printf(" "); + printf("%d", val); + } + printf("\n"); + } + return 0; +} diff --git a/math/pow_of_matrix/hash.json b/math/pow_of_matrix/hash.json new file mode 100644 index 000000000..c2d6bce4c --- /dev/null +++ b/math/pow_of_matrix/hash.json @@ -0,0 +1,66 @@ +{ + "example_00.in": "8c96d051dc1252449299b5cfb3b06c466f5cb0194f97172b33f5078642c1fb61", + "example_00.out": "b014e72211237f7f5001f372abe2082ea85fa3c7bb6ddda3778000eb5739a381", + "example_01.in": "81f6b4247d80a09621f0747ab246f4e707c0fc3926b0c1f522ac493e5b5eae97", + "example_01.out": "bf284252c00be268976cb5f85fe21220797083556c200aa90e9f159123e71873", + "example_02.in": "679e0c7dd8b57266890588b436e127e6bed407dd7cc92d7eac0b9f0914f3ef1e", + "example_02.out": "2f8dbf0dd57f04a042edb45647bbe4d0d50862d5086dcc4dacefacf8ea8e7a00", + "lowrank_max_random_00.in": "ea3ae3425946931d851a1db4d661468b6fb08fd92b8efe0ac01d60d60a1886ab", + "lowrank_max_random_00.out": "06f2597a17232e81af8683f6cd9989112e0e4a23fb82143f13ec4dfc753abd6e", + "lowrank_max_random_01.in": "5e3518e4a510bdb890e411179fa01f8bd41d418a929175a5609ce32c142bf878", + "lowrank_max_random_01.out": "82ba96ded3c793f7a454675dd7816298aa5c4657d5d67e85fa18b9e0613c3b36", + "max_random_00.in": "54f7d64aa5c5ee891ccaade66a0626be24a40017e7454be7e1b1e12524d3ce36", + "max_random_00.out": "d0e392f85f64d16be4d29d2b9cdb5e8ff65bf1e5bdc248c8b986989c2dbe8fe7", + "max_random_01.in": "077a541e659a94478f56fd388874a516956c31d22464bd24fd63085b15177c86", + "max_random_01.out": "ec7ed797d3a222d08345a18ddf4ba0301e8222c49aff33db5e67bd18616300d3", + "max_random_02.in": "bb7f0569218717fcf5dbc09ed54d599afbb66cc5ec38a8b4f7decd90b7f60820", + "max_random_02.out": "d8a902b636c27d77e3e43cb99d29a542012d5718de2b5d1b24a4245de4cc99b5", + "max_random_03.in": "9c48eb180419c4cadb21882448d7cebc789b1c2d86e27d0f026be1fe7abd2a8e", + "max_random_03.out": "0a85424e818527de34b61a68d92b106d0baeee2923f8a5e45e748ff4f41f3bf5", + "max_random_worst_00.in": "8bab459f1937906aa7d1ab4731b8ceb8fd24cbb13398785d6b64c57ca3f96c64", + "max_random_worst_00.out": "5b425c3c5d12e9c120f29c0f76c1ad582a9dad09a6d9099f2a6455195e8e5cd2", + "max_random_worst_01.in": "d99d119f3a52ca6066a99d42ba363e184d10b0d73cf6a1a752b44fa171b446fa", + "max_random_worst_01.out": "cb2c717e217aa1057dd92c047959ec9c6c42688a2f96f8c27f2a65eb35a8f6ca", + "max_random_worst_02.in": "49d58655ab64c821bfcec7450aa1ebecd6d9da5baac7b14dc29e948aa60ef858", + "max_random_worst_02.out": "76af4dc33e2d5c3feca7675bb8ded9affc5611d8775250fcac64aecb5912f82d", + "max_random_worst_03.in": "6ce66c9e829521fa1d416295348188d90e91e7d09b17d8a071565faf1a4618ab", + "max_random_worst_03.out": "0dfd9d4f2a6bdce3d9a8d45fe41cc60d560f7fd9f2150e0872a2810a1aa4861c", + "perm_max_random_00.in": "1a4c32f645aa0b2243ddff51630762e9ec352c58f40b2a3df1a99d9d8c176aa0", + "perm_max_random_00.out": "21a6b93cfa8aa616d60cd65ccbfecb7c98dc11dad8f23634a80055661608f3ab", + "perm_max_random_01.in": "866a0a66eb3d683e7150ccacc7c1d4885b555773459b4d45678654190c68414a", + "perm_max_random_01.out": "8e736a59917e0cf4b7744cef2d05ba6807c5b81ce9728da66ffe3e0e049c0652", + "random_00.in": "d9edb3b8efa26b8c40c708f37813a2ff44fffdc56a02af4ef0594e01dbc1b064", + "random_00.out": "af7a1ed00b25420cd595b792e945f79b4d149ae7fac87fbff3b4916f6cbbbd66", + "random_01.in": "18ff31aba7fd51754c0a37dad9260ccbfd9154603e948cd15afe9fee0426bfe9", + "random_01.out": "b33e04f85d2776d80130df76a1904921c3a714d38b46f47d09f78243ee2efa7c", + "random_02.in": "1bd68099f35fbde28c7a157c23be1743385903faaf927578b21320bbf6434e1b", + "random_02.out": "a6c239f0ec88f89641f4097afb7b83e365e6a76f5c60ac5142df8ddb90593fc5", + "signed_overflow_00.in": "cf53f3409bc01d23426bd52be940d4f5d02c1c30edad154a78e7c941cb7d347d", + "signed_overflow_00.out": "6811813e34ad291d293d8ec1807056845cc5f896ec3dd96877cfd74e02bd7d53", + "small_00.in": "3c45b1eda0cb7bcadd7f25fbcccb38d63b60f0a6aee84b54f8bce38d1a6e8c07", + "small_00.out": "4355a46b19d348dc2f57c046f8ef63d4538ebb936000f3c9ee954a27460dd865", + "small_01.in": "30844f59c667ed9b2501ec8e962f73f5ff242e931eb0ae9e94500ba395396dea", + "small_01.out": "70b2e20a859896a187c305eb3029848afd081fda4405f3ceb20285893410b217", + "small_02.in": "889ac6326529e21ac65f92e51846473fbe52ae6cb10a4644e55ced3015130db9", + "small_02.out": "bf284252c00be268976cb5f85fe21220797083556c200aa90e9f159123e71873", + "small_03.in": "ef7e985afdac0c67aa8a69681da734108b76f7c28e4dd59e40674593478677ea", + "small_03.out": "af3f76179322d5f9409d5fc655ae7f5e6ec6a572a0df43e580f552cbea13a9f2", + "small_04.in": "7c97dd267f6eb89f1b6313a78fc9998b3bfb475e45947479c178e0bb7c9e81d0", + "small_04.out": "cb76b5777ca834f966699ad212c68c3a056f7e749753736d80634f733ce1f7de", + "small_05.in": "de0a02afd7d1c85e76e5acc85b6be04c594e454a1b7a1e38ef49670490628b45", + "small_05.out": "4c9c3181f5a709a3af94947957f802409023802aa93c09698b4ac527c252c1dc", + "small_06.in": "5b60e41f367aea1ce1b1e74a9207470ac98dfd3524416fb2e6b6510c359a82bd", + "small_06.out": "b478b81b481e9c31746e6bb8761fa88553aa2fab0a8daa52dd51794699af5442", + "small_07.in": "e3031bda06a6d9d0c23fa208c25935626561a411b3616d0ea3a765285b58fcac", + "small_07.out": "2144ca19e9da783620e89cf7c0fa1c7b1aeb796b14ca9cf6c7025437a3920575", + "small_08.in": "78a81435da48a049189333778318a0fc4c6893364948133e3dd8545dec1c53f5", + "small_08.out": "0cf040b24cd023ef08ff924761ffcc76cb41b940d0390351d97c2aaee346d853", + "small_09.in": "1b6b05ebb30916894e7e44b8e0b729bb418870fabc254a120fa3f45b94ed2262", + "small_09.out": "f13b831ceaa02fc1eb3c79061ac9b34de17677df88448cc9d8994d6b28dd60c5", + "small_10.in": "44026854bfdb4ae1ca269bc6f3dcdfe728a64dbd1e2852f0e354d9f514988615", + "small_10.out": "50c0344d39ce80562bd1abef1a234745245de007af37752a72f526772f88e353", + "small_11.in": "fcd810efd07cd65684a9175aa2c160f02827a6f20e6a5a185e87d336bfdd6ab1", + "small_11.out": "6ed9021c9cc90afc948cfc9d8e1dd3b56f38bfb7d7566e6876a4aa7aa8f4f804", + "unsigned_overflow_00.in": "52d993215eb7fa8f0a370bd8cf58cfe9d49b99d9a12bdc59db247e6e74631e3b", + "unsigned_overflow_00.out": "7eadc006d6ec87ec0908f0f1a9093fdeddd57514ac0315c4c8655d4c215b5be5" +} \ No newline at end of file diff --git a/math/pow_of_matrix/info.toml b/math/pow_of_matrix/info.toml new file mode 100644 index 000000000..13a099b00 --- /dev/null +++ b/math/pow_of_matrix/info.toml @@ -0,0 +1,36 @@ +title = 'Pow of Matrix' +timelimit = 5.0 +forum = "https://github.com/yosupo06/library-checker-problems/issues/567" + +[[tests]] + name = "example.in" + number = 3 +[[tests]] + name = "random.cpp" + number = 3 +[[tests]] + name = "small.cpp" + number = 12 +[[tests]] + name = "max_random.cpp" + number = 4 +[[tests]] + name = "max_random_worst.cpp" + number = 4 +[[tests]] + name = "lowrank_max_random.cpp" + number = 2 +[[tests]] + name = "perm_max_random.cpp" + number = 2 +[[tests]] + name = "signed_overflow.cpp" + number = 1 +[[tests]] + name = "unsigned_overflow.cpp" + number = 1 + +[params] + N_MAX = 200 + K_MAX = 1000000000000000000 + MOD = 998244353 diff --git a/math/pow_of_matrix/sol/correct.cpp b/math/pow_of_matrix/sol/correct.cpp new file mode 100644 index 000000000..11a24a7dc --- /dev/null +++ b/math/pow_of_matrix/sol/correct.cpp @@ -0,0 +1,317 @@ +#include +#include +#include + +using namespace std; + +using ll = long long; +using u32 = unsigned int; +using u64 = unsigned long long; +using i128 = __int128; +using u128 = unsigned __int128; +using f128 = __float128; + +using vi = vector; +template +using vc = vector; +template +using vvc = vector>; + +#define vv(type, name, h, ...) \ + vector> name(h, vector(__VA_ARGS__)) + +#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 + +#define eb emplace_back +#define mp make_pair +#define mt make_tuple +#define fi first +#define se second + +#line 1 "library/other/io.hpp" +// based on yosupo's fastio +#include + +#line 2 "library/mod/modint_common.hpp" + +struct has_mod_impl { + template + static auto check(T &&x) -> decltype(x.get_mod(), std::true_type{}); + template + static auto check(...) -> std::false_type; +}; + +template +class has_mod : public decltype(has_mod_impl::check(std::declval())) {}; + +template +mint inv(int n) { + static const int mod = mint::get_mod(); + static vector dat = {0, 1}; + assert(0 <= n); + if (n >= mod) n %= mod; + while (len(dat) <= n) { + int k = len(dat); + int q = (mod + k - 1) / k; + dat.eb(dat[k * q - mod] * mint::raw(q)); + } + return dat[n]; +} + +template +mint fact(int n) { + static const int mod = mint::get_mod(); + assert(0 <= n && n < mod); + static vector dat = {1, 1}; + while (len(dat) <= n) dat.eb(dat[len(dat) - 1] * mint::raw(len(dat))); + return dat[n]; +} + +template +mint fact_inv(int n) { + static vector dat = {1, 1}; + if (n < 0) return mint(0); + while (len(dat) <= n) dat.eb(dat[len(dat) - 1] * inv(len(dat))); + return dat[n]; +} + +template +mint fact_invs(Ts... xs) { + return (mint(1) * ... * fact_inv(xs)); +} + +template +mint multinomial(Head &&head, Tail &&... tail) { + return fact(head) * fact_invs(std::forward(tail)...); +} + +template +mint C_dense(int n, int k) { + static vvc C; + static int H = 0, W = 0; + auto calc = [&](int i, int j) -> mint { + if (i == 0) return (j == 0 ? mint(1) : mint(0)); + return C[i - 1][j] + (j ? C[i - 1][j - 1] : 0); + }; + if (W <= k) { + FOR(i, H) { + C[i].resize(k + 1); + FOR(j, W, k + 1) { C[i][j] = calc(i, j); } + } + W = k + 1; + } + if (H <= n) { + C.resize(n + 1); + FOR(i, H, n + 1) { + C[i].resize(W); + FOR(j, W) { C[i][j] = calc(i, j); } + } + H = n + 1; + } + return C[n][k]; +} + +template +mint C(ll n, ll k) { + assert(n >= 0); + if (k < 0 || n < k) return 0; + if constexpr (dense) return C_dense(n, k); + if constexpr (!large) return multinomial(n, k, n - k); + k = min(k, n - k); + mint x(1); + FOR(i, k) x *= mint(n - i); + return x * fact_inv(k); +} + +template +mint C_inv(ll n, ll k) { + assert(n >= 0); + assert(0 <= k && k <= n); + if (!large) return fact_inv(n) * fact(k) * fact(n - k); + return mint(1) / C(n, k); +} + +// [x^d](1-x)^{-n} +template +mint C_negative(ll n, ll d) { + assert(n >= 0); + if (d < 0) return mint(0); + if (n == 0) { return (d == 0 ? mint(1) : mint(0)); } + return C(n + d - 1, d); +} +#line 3 "library/mod/modint.hpp" + +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(u32 x) : val(x % umod) {} + constexpr modint(u64 x) : val(x % umod) {} + constexpr modint(int x) : val((x %= mod) < 0 ? x + mod : x){}; + constexpr modint(ll x) : val((x %= mod) < 0 ? x + mod : x){}; + bool operator<(const modint &other) const { return val < other.val; } + 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); + } + modint pow(ll n) const { + assert(n >= 0); + modint ret(1), mul(val); + while (n > 0) { + if (n & 1) ret *= mul; + mul *= mul; + n >>= 1; + } + return ret; + } +#ifdef FASTIO + void write() { fastio::printer.write(val); } + void read() { + fastio::scanner.read(val); + val %= mod; + } +#endif + static constexpr int get_mod() { return mod; } + // (n, r), r は 1 の 2^n 乗根 + static constexpr pair ntt_info() { + if (mod == 167772161) return {25, 17}; + if (mod == 469762049) return {26, 30}; + if (mod == 754974721) return {24, 362}; + if (mod == 880803841) return {23, 211}; + if (mod == 943718401) return {22, 663003469}; + if (mod == 998244353) return {23, 31}; + if (mod == 1045430273) return {20, 363}; + if (mod == 1051721729) return {20, 330}; + if (mod == 1053818881) return {20, 2789}; + return {-1, -1}; + } + static constexpr bool can_ntt() { return ntt_info().fi != -1; } +}; + +using modint107 = modint<1000000007>; +using modint998 = modint<998244353>; +#line 3 "library/linalg/matrix_mul.hpp" + +template ::value>::type * = nullptr> +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]); } + vv(u32, b, N3, N2); + FOR(i, N2) FOR(j, N3) b[j][i] = B[i][j].val; + vv(T, C, N1, N3); + + if ((T::get_mod() < (1 << 30)) && N2 <= 16) { + FOR(i, N1) FOR(j, N3) { + u64 sm = 0; + FOR(m, N2) sm += u64(A[i][m].val) * b[j][m]; + C[i][j] = sm; + } + } else { + FOR(i, N1) FOR(j, N3) { + u128 sm = 0; + FOR(m, N2) sm += u64(A[i][m].val) * b[j][m]; + C[i][j] = T::raw(sm % (T::get_mod())); + } + } + return C; +} + +template ::value>::type * = nullptr> +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]); } + vv(T, b, N2, N3); + FOR(i, N2) FOR(j, N3) b[j][i] = B[i][j]; + vv(T, C, N1, N3); + FOR(n, N1) FOR(m, N2) FOR(k, N3) C[n][k] += A[n][m] * b[k][m]; + return C; +} +#line 2 "library/linalg/matrix_pow.hpp" + +template +vc> matrix_pow(vc> A, ll n) { + int N = len(A); + vv(T, ret, N, N); + FOR(i, N) ret[i][i] = T(1); + while (n) { + if (n & 1) ret = matrix_mul(ret, A, N, N, N); + n /= 2; + if (n) A = matrix_mul(A, A, N, N, N); + } + return ret; +} +#line 6 "main.cpp" +using mint = modint998; + +void solve() { + ll N, K; + scanf("%lld %lld", &N, &K); + vv(mint, A, N, N); + FOR(i, N) FOR(j, N) { + int x; + scanf("%d", &x); + A[i][j] = x; + } + A = matrix_pow(A, K); + FOR(i, N) { + FOR(j, N) { + if (j) printf(" "); + printf("%d", A[i][j].val); + } + printf("\n"); + } +} + +signed main() { + solve(); + return 0; +} diff --git a/math/pow_of_matrix/task.md b/math/pow_of_matrix/task.md new file mode 100644 index 000000000..fe96f35cb --- /dev/null +++ b/math/pow_of_matrix/task.md @@ -0,0 +1,39 @@ +## @{keyword.statement} + +@{lang.en} +Given $N \times N$ matrix $A = \lbrace a_{ij} \rbrace$ with entries in $\mathbb{Z}/@{param.MOD}\mathbb{Z}$, and a non-negative integer $K$. +print $A^K = (b_{ij})_{i,j}$. +@{lang.ja} +$\mathbb{Z}/@{param.MOD}\mathbb{Z}$ 成分の $N \times N$ 正方行列 $A=a_{ij}$ および非負整数 $K$ が与えられます.$A^K = (b_{ij})_{i,j}$ を求めてください. +@{lang.end} + +## @{keyword.constraints} + +- $1 \leq N \leq @{param.N_MAX}$ +- $0 \leq K \leq @{param.K_MAX}$ +- $0 \leq a_{ij} < @{param.MOD}$ + +## @{keyword.input} + +``` +$N$ $K$ +$a_{11}$ $a_{12}$ ... $a_{1N}$ +$a_{21}$ $a_{22}$ ... $a_{2N}$ +: +$a_{N1}$ $a_{N2}$ ... $a_{NN}$ +``` + +## @{keyword.output} + +``` +$b_{11}$ $b_{12}$ ... $b_{1N}$ +$b_{21}$ $b_{22}$ ... $b_{2N}$ +: +$b_{N1}$ $b_{N2}$ ... $b_{NN}$ +``` + +## @{keyword.sample} + +@{example.example_00} + +@{example.example_01} diff --git a/math/pow_of_matrix/verifier.cpp b/math/pow_of_matrix/verifier.cpp new file mode 100644 index 000000000..4b5aabe38 --- /dev/null +++ b/math/pow_of_matrix/verifier.cpp @@ -0,0 +1,22 @@ +#include + +#include "testlib.h" +#include "params.h" + +int main() { + registerValidation(); + + int n = inf.readInt(1, N_MAX); + inf.readSpace(); + inf.readLong(0LL, K_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 52ccfe7e2c9f0b6a9ca3195ca23e859d4f25ec43 Mon Sep 17 00:00:00 2001 From: maspypy Date: Sun, 5 Nov 2023 02:33:03 +0900 Subject: [PATCH 2/3] reduce template --- math/pow_of_matrix/sol/correct.cpp | 157 ++--------------------------- 1 file changed, 6 insertions(+), 151 deletions(-) diff --git a/math/pow_of_matrix/sol/correct.cpp b/math/pow_of_matrix/sol/correct.cpp index 11a24a7dc..d03fe707d 100644 --- a/math/pow_of_matrix/sol/correct.cpp +++ b/math/pow_of_matrix/sol/correct.cpp @@ -7,9 +7,7 @@ using namespace std; using ll = long long; using u32 = unsigned int; using u64 = unsigned long long; -using i128 = __int128; using u128 = unsigned __int128; -using f128 = __float128; using vi = vector; template @@ -42,119 +40,6 @@ using vvc = vector>; #define fi first #define se second -#line 1 "library/other/io.hpp" -// based on yosupo's fastio -#include - -#line 2 "library/mod/modint_common.hpp" - -struct has_mod_impl { - template - static auto check(T &&x) -> decltype(x.get_mod(), std::true_type{}); - template - static auto check(...) -> std::false_type; -}; - -template -class has_mod : public decltype(has_mod_impl::check(std::declval())) {}; - -template -mint inv(int n) { - static const int mod = mint::get_mod(); - static vector dat = {0, 1}; - assert(0 <= n); - if (n >= mod) n %= mod; - while (len(dat) <= n) { - int k = len(dat); - int q = (mod + k - 1) / k; - dat.eb(dat[k * q - mod] * mint::raw(q)); - } - return dat[n]; -} - -template -mint fact(int n) { - static const int mod = mint::get_mod(); - assert(0 <= n && n < mod); - static vector dat = {1, 1}; - while (len(dat) <= n) dat.eb(dat[len(dat) - 1] * mint::raw(len(dat))); - return dat[n]; -} - -template -mint fact_inv(int n) { - static vector dat = {1, 1}; - if (n < 0) return mint(0); - while (len(dat) <= n) dat.eb(dat[len(dat) - 1] * inv(len(dat))); - return dat[n]; -} - -template -mint fact_invs(Ts... xs) { - return (mint(1) * ... * fact_inv(xs)); -} - -template -mint multinomial(Head &&head, Tail &&... tail) { - return fact(head) * fact_invs(std::forward(tail)...); -} - -template -mint C_dense(int n, int k) { - static vvc C; - static int H = 0, W = 0; - auto calc = [&](int i, int j) -> mint { - if (i == 0) return (j == 0 ? mint(1) : mint(0)); - return C[i - 1][j] + (j ? C[i - 1][j - 1] : 0); - }; - if (W <= k) { - FOR(i, H) { - C[i].resize(k + 1); - FOR(j, W, k + 1) { C[i][j] = calc(i, j); } - } - W = k + 1; - } - if (H <= n) { - C.resize(n + 1); - FOR(i, H, n + 1) { - C[i].resize(W); - FOR(j, W) { C[i][j] = calc(i, j); } - } - H = n + 1; - } - return C[n][k]; -} - -template -mint C(ll n, ll k) { - assert(n >= 0); - if (k < 0 || n < k) return 0; - if constexpr (dense) return C_dense(n, k); - if constexpr (!large) return multinomial(n, k, n - k); - k = min(k, n - k); - mint x(1); - FOR(i, k) x *= mint(n - i); - return x * fact_inv(k); -} - -template -mint C_inv(ll n, ll k) { - assert(n >= 0); - assert(0 <= k && k <= n); - if (!large) return fact_inv(n) * fact(k) * fact(n - k); - return mint(1) / C(n, k); -} - -// [x^d](1-x)^{-n} -template -mint C_negative(ll n, ll d) { - assert(n >= 0); - if (d < 0) return mint(0); - if (n == 0) { return (d == 0 ? mint(1) : mint(0)); } - return C(n + d - 1, d); -} -#line 3 "library/mod/modint.hpp" - template struct modint { static constexpr u32 umod = u32(mod); @@ -213,15 +98,7 @@ struct modint { } return ret; } -#ifdef FASTIO - void write() { fastio::printer.write(val); } - void read() { - fastio::scanner.read(val); - val %= mod; - } -#endif static constexpr int get_mod() { return mod; } - // (n, r), r は 1 の 2^n 乗根 static constexpr pair ntt_info() { if (mod == 167772161) return {25, 17}; if (mod == 469762049) return {26, 30}; @@ -237,11 +114,9 @@ struct modint { static constexpr bool can_ntt() { return ntt_info().fi != -1; } }; -using modint107 = modint<1000000007>; using modint998 = modint<998244353>; -#line 3 "library/linalg/matrix_mul.hpp" -template ::value>::type * = nullptr> +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]); } @@ -249,34 +124,14 @@ vc> matrix_mul(const vc> &A, const vc> &B, int N1 = -1, FOR(i, N2) FOR(j, N3) b[j][i] = B[i][j].val; vv(T, C, N1, N3); - if ((T::get_mod() < (1 << 30)) && N2 <= 16) { - FOR(i, N1) FOR(j, N3) { - u64 sm = 0; - FOR(m, N2) sm += u64(A[i][m].val) * b[j][m]; - C[i][j] = sm; - } - } else { - FOR(i, N1) FOR(j, N3) { - u128 sm = 0; - FOR(m, N2) sm += u64(A[i][m].val) * b[j][m]; - C[i][j] = T::raw(sm % (T::get_mod())); - } + FOR(i, N1) FOR(j, N3) { + u128 sm = 0; + FOR(m, N2) sm += u64(A[i][m].val) * b[j][m]; + C[i][j] = T::raw(sm % (T::get_mod())); } return C; } -template ::value>::type * = nullptr> -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]); } - vv(T, b, N2, N3); - FOR(i, N2) FOR(j, N3) b[j][i] = B[i][j]; - vv(T, C, N1, N3); - FOR(n, N1) FOR(m, N2) FOR(k, N3) C[n][k] += A[n][m] * b[k][m]; - return C; -} -#line 2 "library/linalg/matrix_pow.hpp" - template vc> matrix_pow(vc> A, ll n) { int N = len(A); @@ -289,7 +144,7 @@ vc> matrix_pow(vc> A, ll n) { } return ret; } -#line 6 "main.cpp" + using mint = modint998; void solve() { From 6332e9559a066e029062ca765e715563c8ea0810 Mon Sep 17 00:00:00 2001 From: maspypy <45988013+maspypy@users.noreply.github.com> Date: Mon, 13 Nov 2023 02:29:51 +0900 Subject: [PATCH 3/3] Update info.toml --- math/pow_of_matrix/info.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/math/pow_of_matrix/info.toml b/math/pow_of_matrix/info.toml index 13a099b00..fc950b65c 100644 --- a/math/pow_of_matrix/info.toml +++ b/math/pow_of_matrix/info.toml @@ -32,5 +32,5 @@ forum = "https://github.com/yosupo06/library-checker-problems/issues/567" [params] N_MAX = 200 - K_MAX = 1000000000000000000 + K_MAX = 1_000_000_000_000_000_000 MOD = 998244353