diff --git a/convolution/min_plus_convolution_concave_arbitrary/checker.cpp b/convolution/min_plus_convolution_concave_arbitrary/checker.cpp new file mode 100644 index 00000000..6a66d533 --- /dev/null +++ b/convolution/min_plus_convolution_concave_arbitrary/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/convolution/min_plus_convolution_concave_arbitrary/gen/common.hpp b/convolution/min_plus_convolution_concave_arbitrary/gen/common.hpp new file mode 100644 index 00000000..fd0393f9 --- /dev/null +++ b/convolution/min_plus_convolution_concave_arbitrary/gen/common.hpp @@ -0,0 +1,50 @@ + +using namespace std; +using ll = long long; + +vector rand_gen(Random& gen, int N, int min_slope, int max_slope) { + vector A(N); + while (1) { + vector slope(N - 1); + for (int i = 0; i < N - 1; ++i) { + slope[i] = gen.uniform(min_slope, max_slope); + } + sort(slope.begin(), slope.end()); + for (int i = 0; i < N - 1; ++i) A[i + 1] = A[i] + slope[i]; + ll mi = *(min_element(A.begin(), A.end())); + ll ma = *(max_element(A.begin(), A.end())); + if (ma - mi > A_MAX) continue; + for (int i = 0; i < N; ++i) A[i] -= mi; + ma -= mi; + int add = gen.uniform(0, A_MAX - ma); + for (int i = 0; i < N; ++i) A[i] += add; + break; + } + return A; +} + +vector rand_B(Random& gen, int N) { + vector B(N); + for (int i = 0; i < N; ++i) B[i] = gen.uniform(A_MIN, A_MAX); + return B; +} + +void upside_down(vector& A){ + int N = A.size(); + for (int i = 0; i < N; ++i) A[i] = A_MAX + A_MIN - A[i]; +} + +void out(vector& A, vector& B) { + int n = A.size(), m = B.size(); + printf("%d %d\n", n, m); + for (int i = 0; i < n; ++i) { + if (i) printf(" "); + printf("%lld", A[i]); + } + printf("\n"); + for (int i = 0; i < m; ++i) { + if (i) printf(" "); + printf("%lld", B[i]); + } + printf("\n"); +} \ No newline at end of file diff --git a/convolution/min_plus_convolution_concave_arbitrary/gen/example_00.in b/convolution/min_plus_convolution_concave_arbitrary/gen/example_00.in new file mode 100644 index 00000000..c56bd90f --- /dev/null +++ b/convolution/min_plus_convolution_concave_arbitrary/gen/example_00.in @@ -0,0 +1,3 @@ +4 5 +0 2 3 1 +5 1 3 3 2 diff --git a/convolution/min_plus_convolution_concave_arbitrary/gen/hack_00.in b/convolution/min_plus_convolution_concave_arbitrary/gen/hack_00.in new file mode 100644 index 00000000..52d0e58f --- /dev/null +++ b/convolution/min_plus_convolution_concave_arbitrary/gen/hack_00.in @@ -0,0 +1,3 @@ +17 8 +127 127 126 124 121 117 112 106 99 91 82 72 61 49 36 22 7 +100000 100000 100000 100000 100000 100000 100000 2 diff --git a/convolution/min_plus_convolution_concave_arbitrary/gen/large_small.cpp b/convolution/min_plus_convolution_concave_arbitrary/gen/large_small.cpp new file mode 100644 index 00000000..4f7fb2b1 --- /dev/null +++ b/convolution/min_plus_convolution_concave_arbitrary/gen/large_small.cpp @@ -0,0 +1,26 @@ +#include +#include "../params.h" +#include "random.h" +#include + +#include "common.hpp" + +int main(int, char* argv[]) { + long long seed = atoll(argv[1]); + auto gen = Random(seed); + + int ns[] = {N_MAX, N_MAX, 1, 2}; + int ms[] = {1, 2, N_MAX, N_MAX}; + + int n = ns[seed % 4]; + int m = ms[seed % 4]; + + int LIM_1 = A_MAX / n; + + vector A = rand_gen(gen, n, -LIM_1, +LIM_1); + vector B = rand_B(gen, m); + upside_down(A); + out(A, B); + + return 0; +} diff --git a/convolution/min_plus_convolution_concave_arbitrary/gen/max_random.cpp b/convolution/min_plus_convolution_concave_arbitrary/gen/max_random.cpp new file mode 100644 index 00000000..e3e411a7 --- /dev/null +++ b/convolution/min_plus_convolution_concave_arbitrary/gen/max_random.cpp @@ -0,0 +1,23 @@ +#include +#include "../params.h" +#include "random.h" +#include + +#include "common.hpp" + +int main(int, char* argv[]) { + long long seed = atoll(argv[1]); + auto gen = Random(seed); + + int n = N_MAX; + int m = N_MAX; + + int LIM_1 = A_MAX / n * 3; + + vector A = rand_gen(gen, n, -LIM_1, +LIM_1); + vector B = rand_B(gen, m); + upside_down(A); + out(A, B); + + return 0; +} diff --git a/convolution/min_plus_convolution_concave_arbitrary/gen/med_random.cpp b/convolution/min_plus_convolution_concave_arbitrary/gen/med_random.cpp new file mode 100644 index 00000000..66a6ad89 --- /dev/null +++ b/convolution/min_plus_convolution_concave_arbitrary/gen/med_random.cpp @@ -0,0 +1,23 @@ +#include +#include "../params.h" +#include "random.h" +#include + +#include "common.hpp" + +int main(int, char* argv[]) { + long long seed = atoll(argv[1]); + auto gen = Random(seed); + + int n = gen.uniform(100, 1000); + int m = gen.uniform(100, 1000); + + int LIM_1 = A_MAX / n * 3; + + vector A = rand_gen(gen, n, -LIM_1, +LIM_1); + vector B = rand_B(gen, m); + upside_down(A); + out(A, B); + + return 0; +} diff --git a/convolution/min_plus_convolution_concave_arbitrary/gen/monotone.cpp b/convolution/min_plus_convolution_concave_arbitrary/gen/monotone.cpp new file mode 100644 index 00000000..d6b910fd --- /dev/null +++ b/convolution/min_plus_convolution_concave_arbitrary/gen/monotone.cpp @@ -0,0 +1,37 @@ +#include +#include "../params.h" +#include "random.h" +#include + +#include "common.hpp" + +int main(int, char* argv[]) { + long long seed = atoll(argv[1]); + auto gen = Random(seed); + + int n = N_MAX; + int m = N_MAX; + + int LIM = A_MAX / n * 2; + int lo_1 = (seed & 1 ? -LIM : 0); + int hi_1 = (seed & 1 ? 0 : LIM); + + vector A = rand_gen(gen, n, lo_1, hi_1); + vector B = rand_B(gen, m); + sort(B.begin(), B.end()); + if (seed & 2) reverse(B.begin(), B.end()); + + for (int i = 0; i < n - 1; ++i) { + if (!(seed & 1)) assert(A[i] <= A[i + 1]); + if (seed & 1) assert(A[i] >= A[i + 1]); + } + for (int i = 0; i < m - 1; ++i) { + if (!(seed & 2)) assert(B[i] <= B[i + 1]); + if (seed & 2) assert(B[i] >= B[i + 1]); + } + + upside_down(A); + out(A, B); + + return 0; +} diff --git a/convolution/min_plus_convolution_concave_arbitrary/gen/near_power_of_2.cpp b/convolution/min_plus_convolution_concave_arbitrary/gen/near_power_of_2.cpp new file mode 100644 index 00000000..6096528e --- /dev/null +++ b/convolution/min_plus_convolution_concave_arbitrary/gen/near_power_of_2.cpp @@ -0,0 +1,28 @@ +#include +#include "../params.h" +#include "random.h" +#include + +#include "common.hpp" + +int main(int, char* argv[]) { + long long seed = atoll(argv[1]); + auto gen = Random(seed); + + int X = 1 << 18; + int a = X - 1, b = X, c = X + 1; + int ns[] = {a, a, a, b, b, b, c, c, c}; + int ms[] = {a, b, c, a, b, c, a, b, c}; + + int n = ns[seed % 9]; + int m = ms[seed % 9]; + + int LIM_1 = A_MAX / n * 3; + + vector A = rand_gen(gen, n, -LIM_1, +LIM_1); + vector B = rand_B(gen, m); + upside_down(A); + out(A, B); + + return 0; +} diff --git a/convolution/min_plus_convolution_concave_arbitrary/gen/only_first_small.cpp b/convolution/min_plus_convolution_concave_arbitrary/gen/only_first_small.cpp new file mode 100644 index 00000000..0fa79b3b --- /dev/null +++ b/convolution/min_plus_convolution_concave_arbitrary/gen/only_first_small.cpp @@ -0,0 +1,30 @@ +#include +#include "../params.h" +#include "random.h" +#include + +#include "common.hpp" + +int main(int, char* argv[]) { + long long seed = atoll(argv[1]); + auto gen = Random(seed); + + int n = N_MAX; + int m = N_MAX; + + int LIM_1 = A_MAX / n * 3; + + vector A = rand_gen(gen, n, -LIM_1, +LIM_1); + vector B(m); + for (int i = 0; i < m; ++i) { + B[i] = gen.uniform(A_MAX * 9 / 10, A_MAX); + } + + int idx = (seed % 2 == 0 ? 0 : m - 1); + B[idx] = A_MIN; + + upside_down(A); + out(A, B); + + return 0; +} diff --git a/convolution/min_plus_convolution_concave_arbitrary/gen/random.cpp b/convolution/min_plus_convolution_concave_arbitrary/gen/random.cpp new file mode 100644 index 00000000..e6c0b802 --- /dev/null +++ b/convolution/min_plus_convolution_concave_arbitrary/gen/random.cpp @@ -0,0 +1,23 @@ +#include +#include "../params.h" +#include "random.h" +#include + +#include "common.hpp" + +int main(int, char* argv[]) { + long long seed = atoll(argv[1]); + auto gen = Random(seed); + + int n = gen.uniform(1, N_MAX); + int m = gen.uniform(1, N_MAX); + + int LIM_1 = A_MAX / n * 3; + + vector A = rand_gen(gen, n, -LIM_1, +LIM_1); + vector B = rand_B(gen, m); + upside_down(A); + out(A, B); + + return 0; +} diff --git a/convolution/min_plus_convolution_concave_arbitrary/gen/small.cpp b/convolution/min_plus_convolution_concave_arbitrary/gen/small.cpp new file mode 100644 index 00000000..8fb93885 --- /dev/null +++ b/convolution/min_plus_convolution_concave_arbitrary/gen/small.cpp @@ -0,0 +1,24 @@ +#include +#include "../params.h" +#include "random.h" +#include + +#include "common.hpp" + +int main(int, char* argv[]) { + long long seed = atoll(argv[1]); + auto gen = Random(seed); + + int ns[] = {1, 1, 1, 2, 2, 2, 3, 3, 3}; + int ms[] = {1, 2, 3, 1, 2, 3, 1, 2, 3}; + + int n = ns[seed % 9]; + int m = ms[seed % 9]; + + vector A = rand_gen(gen, n, -A_MAX, +A_MAX); + vector B = rand_B(gen, m); + upside_down(A); + out(A, B); + + return 0; +} diff --git a/convolution/min_plus_convolution_concave_arbitrary/gen/small_slopes.cpp b/convolution/min_plus_convolution_concave_arbitrary/gen/small_slopes.cpp new file mode 100644 index 00000000..1a0adc1c --- /dev/null +++ b/convolution/min_plus_convolution_concave_arbitrary/gen/small_slopes.cpp @@ -0,0 +1,21 @@ +#include +#include "../params.h" +#include "random.h" +#include + +#include "common.hpp" + +int main(int, char* argv[]) { + long long seed = atoll(argv[1]); + auto gen = Random(seed); + + int n = N_MAX; + int m = N_MAX; + + vector A = rand_gen(gen, n, -10, +10); + vector B = rand_B(gen, m); + upside_down(A); + out(A, B); + + return 0; +} diff --git a/convolution/min_plus_convolution_concave_arbitrary/hash.json b/convolution/min_plus_convolution_concave_arbitrary/hash.json new file mode 100644 index 00000000..7a42d993 --- /dev/null +++ b/convolution/min_plus_convolution_concave_arbitrary/hash.json @@ -0,0 +1,84 @@ +{ + "example_00.in": "3f248bae57fe16a6b3b63c0743b53e5da574c4b709aa41b14e4e81ad37251f49", + "example_00.out": "afcbb20cff61b123b64d2feda6e1473486f3444c3186acb8d2ff2c9c823f6a5b", + "hack_00.in": "2790cbcd42ffa6208ad9800a101ab2b4c22cdf148c0a3c794de95a1ea599cd4a", + "hack_00.out": "e58ccf2b3c94da35a211f58352b2f6aff3da42d724f9c50101d1ebe7f036fd4c", + "large_small_00.in": "f8df9037aedd9092a0d0f3dbe7e7c2d0ed1d496b93d8a1a8a21d35745165d3e4", + "large_small_00.out": "e0d5ab1ddb2947ca9d0784f985fd2970481019f79d94f0d1882b34c7e0153fce", + "large_small_01.in": "252533d35d2ec5a238dd8b9e1d7639eec2c959726fd58b87c89ee5896982de3e", + "large_small_01.out": "2370f95670527efe6113c9dea6b458453c7097269daa6dcf408f21b2a560eb0d", + "large_small_02.in": "9168f3bfb7862da498fc043eaa6872793bb75edd62c048898375366caa4dfe00", + "large_small_02.out": "4a735075f308dc62638fd7434cda39fe168fdb17da1cab780e967640040c16c2", + "large_small_03.in": "356dc57ad8a9a518d4ce3c7868ec13024e7af0edaf9e8c213dfb59b1a30202e3", + "large_small_03.out": "e29c4211d6cdfbd9224bec06877b4aec550e96126285228b0cbb4680947e66bc", + "max_random_00.in": "7023bd58d017c7b88a3f93ce3335bb37d797b9196d64a1332437c4d9e8f4e51c", + "max_random_00.out": "41021c8968f79e804afe9fdb95358530ee2610283d6c7578d419bb95c3484fee", + "max_random_01.in": "93b2f1be9813bc0d0a48b47aebf1a85849966bfbb0f308e565e6bbd7e7d2f7c7", + "max_random_01.out": "761a3663150262257cf65048538e9bb7ce42e334408444f30b365ceefc736c16", + "max_random_02.in": "413329b4baa246df9aab3e55e5bff2268fb2393a7b5c58ecece399d29180051f", + "max_random_02.out": "ee3fac52a5c4b3edd5161eb0580fa16da629273be99dfc3f4706df3075173aa7", + "med_random_00.in": "e93b01c36d779123425cc4fb2d72cc692b965d1347e4bd56a0df11d277b14ff5", + "med_random_00.out": "7361aa0f8e261d7a6394518b47150b66259f62c8cdbceb4a62e8cb95f065c5d6", + "med_random_01.in": "254fc9316862e78ccf06236a4710b904a5dcbc624c8e84c9cb7a5f69cbc9f39a", + "med_random_01.out": "14cbe95270c924f668f6b86c1e89447c5ae6885a3d824febd488dc9061abcff7", + "med_random_02.in": "8d742829c47bf7e0292ccaea2090b0a8b9ccf9170b27a0a00d1f3cdb894ad67a", + "med_random_02.out": "edafdd28496182d18403f39e79a98d4f48756052465db78ea548571cd19dffb8", + "monotone_00.in": "9a395b1efc7e9429180ea10bab6cd3eed88b38495ddf8dd439034d14d0ae53e5", + "monotone_00.out": "f2d4d7d84e153cf832651b525e39018aa9ffca1c6424d993a60096a3eaafc207", + "monotone_01.in": "38c8de37e07728e9c3d5baabf236a375d5ca2598bad22da73cb3972b9945a67d", + "monotone_01.out": "44427f85913b5413d6ae83b3971ede67db521db22a6fc6b7f6ec10b724a28747", + "monotone_02.in": "a4e51109a92f32a35072dd444491871b30f97deaa42405c5ad39b28b75d0af4c", + "monotone_02.out": "745b424b292e5b7aa7f60c3828c2a50c5047812a4300af09c558ecc8dc16d8f3", + "monotone_03.in": "28e46f1847c3671f746f5a9ed954aecbad56eb2e1be8d35eacbd67a84e5460a9", + "monotone_03.out": "a2f64d6ab1f8892f17eed0a0f0930f2ba9fbc44bb711e87bbcea7a0a227fcfab", + "near_power_of_2_00.in": "2f86d212ce3e9d0b2b481556ec3e7b4de97754bb45edd9e29901c8d2ed65e104", + "near_power_of_2_00.out": "04797591844a5ee06f596a7faf5956eec9ee7860f87061af630a6d3de16d79eb", + "near_power_of_2_01.in": "2fbb90f7610c5669342c866d3c1152259aa369c8d30abb7463c7ee8619a588d9", + "near_power_of_2_01.out": "e8e43b4a90ea9ffd75d275a17dda4161b82d8667c4878c8acbb185210d577edc", + "near_power_of_2_02.in": "250bb97e5dbca7681cce87d297d8bcb07b414bd70879a52bc65d33d0dab9f1eb", + "near_power_of_2_02.out": "321efe4bc82fe2427575124c72a84bf13e695221d672f51f51dd5e32e7a13050", + "near_power_of_2_03.in": "7fbb267e1fe705dab2fc5b63ac9443502306e552f13450f82aa981823b108087", + "near_power_of_2_03.out": "811bc2cbbb517f5d072f2062958b49db329e0a456d05f0998e48a8dfaf94d3fb", + "near_power_of_2_04.in": "bcd9f3e6cb14e64317a5b262174b6ef603b731e7b3758af9f0a0dfbdf4d468f1", + "near_power_of_2_04.out": "c816ec836ea7d2c6c3d736793c77953ff2bc8d2a03978db8269c26b6478d90f9", + "near_power_of_2_05.in": "616ff84d8fbf0959a4af8a8c74bcc683deae2eadc6f6f079659754c9940874f0", + "near_power_of_2_05.out": "efadb9add7ce3389a738e3e03b705f70ab4493a69d625294081a8e41177b3647", + "near_power_of_2_06.in": "d9e7f33f97d0e4b77cd27a284ce107e3377dc54bc60e326266442a9ed4718e54", + "near_power_of_2_06.out": "fbb1cde067c76b8001ba0a855a66d6901dfaa08a636e24d6c50d830a6dcf1d53", + "near_power_of_2_07.in": "b40cfda2d2428c89b5de817642ca443702cc2d2bf6233803bd934f47a5a8297d", + "near_power_of_2_07.out": "aa8e201138fac27ec3189dfb23201bcb239e10b96b91d8fda8ca9a2b0b086ae4", + "near_power_of_2_08.in": "427385f2f47d0588ff44af9c5873b65e6dbffd13db74fcb90e573ad4a32e21c5", + "near_power_of_2_08.out": "abd53f2257289a27e55801efacb8f34e272ae508e1c07f283c576c618e3d41f3", + "only_first_small_00.in": "5b2629a2a7fcb9ac2f5426f47b832065f5c4525da4aab5554ffe6b1a2d4675ce", + "only_first_small_00.out": "b060d9ea41e4bc137fe68b360b170cf08e6605b6643e479ff3cde3173def2770", + "only_first_small_01.in": "5b402e1496d9341bf0ebd419e849ca1e1d5157572d29540494cb9fc0398e277d", + "only_first_small_01.out": "085bcbc846ba57a2631c756e67f920a42e45df962a8478e70b5154f4a0964311", + "random_00.in": "c5b1d358adf5c02ce4fafe154d2506bb37853d6eccb224cb8918a4ceff07eae0", + "random_00.out": "c34585eaf3266c86b98ea02fea41eab9d34e66265cdbc382e589ad8ee52de786", + "random_01.in": "ff7140f881f9867ceae4e677be50af82eaa0806fe45db6fcec23895504a7ac95", + "random_01.out": "536da5f8d48ac9528b91a993f9efdcb9e1fba571c2661eec9f89f7faa986f043", + "random_02.in": "d67ab8ae479b52145c2b993ce9f50285f86ae580f671b4071cef04a7d41c658e", + "random_02.out": "bb38212721594630d7fc3250ef3e10f68242c11b9cb13e5e03051f9ed37caa3e", + "small_00.in": "bd5a7f2cbe20c36368f5af09d2eb7919625748740baa99518e76835a445726fe", + "small_00.out": "430f0f2d9e0d91e4f2a0072a9c7841e1f3ca9941e97de5adc0a07b0c60b7715a", + "small_01.in": "da0926405459eee4282d14e65e9668a5c0a7751c1ab7e50430a9ef316c3f0024", + "small_01.out": "3c97c192205eb16a2c5f8f8ddf2a7bd79775a260d8b6fcb64fa388d7d45e13b1", + "small_02.in": "8fdc2390e58dcdc9f668b0309043be09b316582ecf0d6358870449a8ac01cb6a", + "small_02.out": "7802293a5a2e4b9e016c430568de50c1767626c78112c14bf1c6be4f2790eba4", + "small_03.in": "dfeeb84628515e76eebe94030843be80c291075bd0327b64f97893f6a8d40624", + "small_03.out": "9f900fbeb6a35ba7ab44e8eaf2a84e4eecea43f2b4961206a78cb8a6b4a4852a", + "small_04.in": "d580838df4d46856c97af6fc78cd471a01fd79a9cbd46768ca2c8a3ef3b380bb", + "small_04.out": "b9d22ac93fc60a758f5e419fcbbb60d0e0408ae2d193f73574172b8d70750d4c", + "small_05.in": "c4a1873f7f6105d77e4c964e00c6b3dbaa3b8fe9b2ad2b5062f147cd2e83d0c4", + "small_05.out": "21641c230ef7cc39ea0afa969b94e822d4e43df2c9790b40ac8e6e3cd9557bdc", + "small_06.in": "939cb5c8dd9870fd2a315d471c52c800e12573e01ae5b8b861e055bebc0a531f", + "small_06.out": "13e1459a241b3f6c649876ea801fc02b13283d5be817b32ba6bdbcb3ad7db7e3", + "small_07.in": "2621399c9f319ae16155daefce41f57d068370ed4866b6c07781b0aef5ca1fab", + "small_07.out": "1f3fd66cff566e520dd156241d820d322aae2dc2a160550d62cd79293f606b09", + "small_08.in": "43b2a4417663df99cc254a9cd0210f3c141cad25f28b797c70869d2a8dfd1e2d", + "small_08.out": "a5351352805a6c73d99ea05553194ca40014b5445d6d9f3716590a18af000994", + "small_slopes_00.in": "ee8972534274bfa318d3443ece5d79393bb69e40b02b84cc38ed907e8d3c9893", + "small_slopes_00.out": "9c2e46d775f028f541f30bd635265452049d83e6e43f6cca6714302283b91a47", + "small_slopes_01.in": "29932d0af66b3147f607708cfd301ff2d91f7862c2d6c20b08773a6bef0314d7", + "small_slopes_01.out": "ccc813ef1f3604a593e20b4428555cc788ee1d01a759abbf6ca3589ddcbe8577" +} \ No newline at end of file diff --git a/convolution/min_plus_convolution_concave_arbitrary/info.toml b/convolution/min_plus_convolution_concave_arbitrary/info.toml new file mode 100644 index 00000000..ecc2392b --- /dev/null +++ b/convolution/min_plus_convolution_concave_arbitrary/info.toml @@ -0,0 +1,56 @@ +title = 'Min Plus Convolution (Concave and Arbitrary)' +timelimit = 5.0 +forum = "https://github.com/yosupo06/library-checker-problems/issues/1252" + +[[tests]] + name = "example.in" + number = 1 + +[[tests]] + name = "small.cpp" + number = 9 + +[[tests]] + name = "med_random.cpp" + number = 3 + +[[tests]] + name = "random.cpp" + number = 3 + +[[tests]] + name = "max_random.cpp" + number = 3 + +[[tests]] + name = "monotone.cpp" + number = 4 + +[[tests]] + name = "small_slopes.cpp" + number = 2 + +[[tests]] + name = "near_power_of_2.cpp" + number = 9 + +[[tests]] + name = "hack.in" + number = 1 + +[[tests]] + name = "large_small.cpp" + number = 4 + +[[tests]] + name = "only_first_small.cpp" + number = 2 + +[[solutions]] + name = "naive.cpp" + allow_tle = true + +[params] + N_MAX = 524288 + A_MIN = 0 + A_MAX = 1000000000 diff --git a/convolution/min_plus_convolution_concave_arbitrary/sol/correct.cpp b/convolution/min_plus_convolution_concave_arbitrary/sol/correct.cpp new file mode 100644 index 00000000..5c3071a2 --- /dev/null +++ b/convolution/min_plus_convolution_concave_arbitrary/sol/correct.cpp @@ -0,0 +1,128 @@ +#include +#include +#include +#include +#include + +using namespace std; + + +template +vector monotone_minima(int h, int w, const FUNC& a) { + vector j_min(h); + + for (int di = 1 << 20; di > 0; di >>= 1) { + int di2 = 2 * di; + for (int i = di; i <= h; i += di2) { + int jL = (i - di > 0 ? j_min[i - di - 1] : 0); + int jR = (i + di <= h ? j_min[i + di - 1] : w - 1); + + int a_min = numeric_limits::max(); + for (int j = jL; j <= jR; j++) { + int val = a(i - 1, j); + + if (a_min > val) { + a_min = val; + j_min[i - 1] = j; + } + } + } + } + + return j_min; +} + + +vector semiconcave_min_plus_convolution(const vector& a, const vector& b) { + int n = (int)a.size(), m = (int)b.size(); + + // b is concave + for (int i = 0; i < m - 2; ++i) assert(b[i] + b[i + 2] <= 2 * b[i + 1]); + + int h = n + m - 1, w = n; + + vector y_min(h, 0), y_max(h, w - 1); + for (int x = m; x <= h - 1; x++) y_min[x] = x - m + 1; + for (int x = 0; x <= h - m; x++) y_max[x] = x; + + vector x_min(w), x_max(w); + for (int y = 0; y < w; y++) { + x_min[y] = y; + x_max[y] = m - 1 + y; + } + + vector c(h, numeric_limits::max()); + + function rf = [&](int x1, int x2, int y1, int y2) { + if (y_max[x1] >= y2 && y1 >= y_min[x2]) { + auto A = [&](int i, int j) { + return a[y2 - j] + b[(x1 + i) - (y2 - j)]; + }; + + auto j_min = monotone_minima(x2 - x1 + 1, y2 - y1 + 1, A); + + for (int i = x1; i <= x2; i++) { + int val = A(i - x1, j_min[i - x1]); + if (c[i] > val) c[i] = val; + } + + return; + } + + if ((long long)(x2 - x1) * (y2 - y1) < 1000) { + for (int x = x1; x <= x2; x++) { + int y_from = max(y_min[x], y1); + int y_to = min(y_max[x], y2); + for (int y = y_from; y <= y_to; y++) { + int val = a[y] + b[x - y]; + if (c[x] > val) c[x] = val; + } + } + return; + } + + if (x2 - x1 > y2 - y1) { + int xm = (x1 + x2) / 2; + + int ny2 = min(y_max[xm], y2); + if (y1 <= ny2) rf(x1, xm, y1, ny2); + + int ny1 = max(y_min[xm], y1); + if (ny1 <= y2) rf(xm + 1, x2, ny1, y2); + } + else { + int ym = (y1 + y2) / 2; + + int nx2 = min(x_max[ym], x2); + if (x1 <= nx2) rf(x1, nx2, y1, ym); + + int nx1 = max(x_min[ym], x1); + if (nx1 <= x2) rf(nx1, x2, ym + 1, y2); + } + }; + rf(0, h - 1, 0, w - 1); + + return c; +} + + +int main() { + int n, m; + scanf("%d %d", &n, &m); + + vector a(n), b(m); + for (int i = 0; i < n; i++) scanf("%d", &a[i]); + for (int j = 0; j < m; j++) scanf("%d", &b[j]); + + vector c = semiconcave_min_plus_convolution(b, a); + + int K = n + m - 1; + for (int k = 0; k < K; k++) { + printf("%d", c[k]); + + if (k < K - 1) printf(" "); + else printf("\n"); + } + + return 0; +} diff --git a/convolution/min_plus_convolution_concave_arbitrary/sol/naive.cpp b/convolution/min_plus_convolution_concave_arbitrary/sol/naive.cpp new file mode 100644 index 00000000..715fb5ad --- /dev/null +++ b/convolution/min_plus_convolution_concave_arbitrary/sol/naive.cpp @@ -0,0 +1,26 @@ +#include +#include +#include +#include + +using namespace std; + +int main() { + int n, m; + scanf("%d %d", &n, &m); + vector a(n), b(m); + for (int i = 0; i < n; ++i) scanf("%d", &a[i]); + for (int i = 0; i < m; ++i) scanf("%d", &b[i]); + vector c(n + m - 1, numeric_limits::max()); + for (int i = 0; i < n; ++i) { + for (int j = 0; j < m; ++j) { + int x = a[i] + b[j]; + if (c[i + j] > x) c[i + j] = x; + } + } + for (int k = 0; k < n + m - 1; ++k) { + if (k) printf(" "); + printf("%d", c[k]); + } + return 0; +} diff --git a/convolution/min_plus_convolution_concave_arbitrary/task.md b/convolution/min_plus_convolution_concave_arbitrary/task.md new file mode 100644 index 00000000..83e8bb94 --- /dev/null +++ b/convolution/min_plus_convolution_concave_arbitrary/task.md @@ -0,0 +1,42 @@ +## @{keyword.statement} + +@{lang.en} +Given integer sequences $a_0, a_1, ..., a_{N - 1}$ and $b_0, b_1, ..., b_{M - 1}$. Here, $a$ is concave. Calculate an integer sequence $c_0, c_1, ..., c_{(N - 1) + (M - 1)}$ defined as follows: + +$$c_k = \min_{i+j=k} (a_i+b_j)$$ + +@{lang.ja} +整数列 $a_0, a_1, ..., a_{N - 1}$、$b_0, b_1, ..., b_{M - 1}$ が与えられます。ここで $a$ は凹です。次のように定義される整数列 $c_0, c_1, ..., c_{(N - 1) + (M - 1)}$ を求めてください。 + +$$c_k = \min_{i+j=k} (a_i+b_j)$$ + +@{lang.end} + +## @{keyword.constraints} + +@{lang.ja} +- $1 \leq N, M \leq @{param.N_MAX}$ +- $0 \leq a_i, b_i \leq @{param.A_MAX}$ +- $a$ は凹である。つまり $0\leq i < N - 2$ に対して $a_{i+1}-a_i\geq a_{i+2}-a_{i+1}$ が成り立つ。 +@{lang.en} +- $1 \leq N, M \leq @{param.N_MAX}$ +- $0 \leq a_i, b_i \leq @{param.A_MAX}$ +- $a$ is concave. i.e. $a_{i+1}-a_i\geq a_{i+2}-a_{i+1}$ holds for $0\leq i < N - 2$. +@{lang.end} +## @{keyword.input} + +``` +$N$ $M$ +$a_0$ $a_1$ ... $a_{N-1}$ +$b_0$ $b_1$ ... $b_{M-1}$ +``` + +## @{keyword.output} + +``` +$c_0$ $c_1$ ... $c_{(N - 1) + (M - 1)}$ +``` + +## @{keyword.sample} + +@{example.example_00} diff --git a/convolution/min_plus_convolution_concave_arbitrary/verifier.cpp b/convolution/min_plus_convolution_concave_arbitrary/verifier.cpp new file mode 100644 index 00000000..178529e2 --- /dev/null +++ b/convolution/min_plus_convolution_concave_arbitrary/verifier.cpp @@ -0,0 +1,38 @@ +#include + +#include "params.h" +#include "testlib.h" + +using namespace std; + +bool is_concave(vector& a) { + int n = a.size(); + for (int i = 0; i < n - 2; ++i) { + if (a[i + 1] - a[i] < a[i + 2] - a[i + 1]) return false; + } + return true; +} + +int main() { + registerValidation(); + int n = inf.readInt(1, N_MAX); + inf.readSpace(); + int m = inf.readInt(1, N_MAX); + inf.readChar('\n'); + vector a(n), b(m); + for (int i = 0; i < n; i++) { + if (i) inf.readSpace(); + a[i] = inf.readInt(A_MIN, A_MAX); + } + inf.readChar('\n'); + for (int i = 0; i < m; i++) { + if (i) inf.readSpace(); + b[i] = inf.readInt(A_MIN, A_MAX); + } + inf.readChar('\n'); + + ensure(is_concave(a)); + + inf.readEof(); + return 0; +}