├── CMakeLists.txt ├── LICENSE ├── README.md ├── gtest ├── CMakeLists.txt ├── cmake │ └── internal_utils.cmake ├── include │ └── gtest │ │ ├── gtest-death-test.h │ │ ├── gtest-message.h │ │ ├── gtest-param-test.h │ │ ├── gtest-param-test.h.pump │ │ ├── gtest-printers.h │ │ ├── gtest-spi.h │ │ ├── gtest-test-part.h │ │ ├── gtest-typed-test.h │ │ ├── gtest.h │ │ ├── gtest_pred_impl.h │ │ ├── gtest_prod.h │ │ └── internal │ │ ├── custom │ │ ├── gtest-port.h │ │ ├── gtest-printers.h │ │ └── gtest.h │ │ ├── gtest-death-test-internal.h │ │ ├── gtest-filepath.h │ │ ├── gtest-internal.h │ │ ├── gtest-linked_ptr.h │ │ ├── gtest-param-util-generated.h │ │ ├── gtest-param-util-generated.h.pump │ │ ├── gtest-param-util.h │ │ ├── gtest-port-arch.h │ │ ├── gtest-port.h │ │ ├── gtest-string.h │ │ ├── gtest-tuple.h │ │ ├── gtest-tuple.h.pump │ │ ├── gtest-type-util.h │ │ └── gtest-type-util.h.pump └── src │ ├── gtest-all.cc │ ├── gtest-death-test.cc │ ├── gtest-filepath.cc │ ├── gtest-internal-inl.h │ ├── gtest-port.cc │ ├── gtest-printers.cc │ ├── gtest-test-part.cc │ ├── gtest-typed-test.cc │ ├── gtest.cc │ └── gtest_main.cc ├── spcppl ├── Bool.hpp ├── CoordinateMinimizer.hpp ├── DSU.hpp ├── Matrix.hpp ├── assert.hpp ├── asserts.hpp ├── binpow.hpp ├── convolution.hpp ├── dataStructures │ ├── BitSet.hpp │ ├── MinQueue.hpp │ ├── NDArray.hpp │ ├── SparseTable.hpp │ ├── TreapMultiset.hpp │ └── segmentTree │ │ ├── BottomUpMaxSegmentTree.hpp │ │ ├── BottomUpMinSegmentTree.hpp │ │ ├── BottomUpSegmentTree.hpp │ │ ├── BottomUpSumSegementTree.hpp │ │ ├── LazyPointSegmentTree.hpp │ │ ├── LazyPointSumSegmentTree.hpp │ │ ├── LazySegmentTree.hpp │ │ ├── SegementTreeBase.hpp │ │ ├── TopDownSegementTree.hpp │ │ └── TopDownSumSegmentTree.hpp ├── fft.hpp ├── flow │ ├── AbsoluteMincostFlowStrategy.hpp │ ├── DinicFlow.hpp │ ├── FixedCostMaxFlowStrategy.hpp │ ├── FixedFlowMIncostStrategy.hpp │ ├── MinCostFlow.hpp │ └── MinCostMaxFlowStrategy.hpp ├── functors │ ├── FunctionIdentity.hpp │ ├── Max.hpp │ ├── Min.hpp │ ├── NegativeInfinity.hpp │ └── PositiveInfinity.hpp ├── gauss │ ├── determinant.hpp │ ├── matrixRank.hpp │ └── reduceToRowEchelonForm.hpp ├── geometry │ ├── Point2D.hpp │ ├── Point3D.hpp │ └── convexHull.hpp ├── graphs │ ├── SimpleGraph.hpp │ ├── VectorVectorBaseGraph.hpp │ ├── WeightedGraph.hpp │ └── algorithms │ │ ├── bfs.hpp │ │ ├── dijkstra.hpp │ │ ├── dynamicConnectivityOffline.hpp │ │ └── findIndependentSetInBipartiteGraph.hpp ├── identity.hpp ├── make_constant.hpp ├── make_vector.hpp ├── matrixMultiplication.hpp ├── numbers │ ├── BigInteger.hpp │ ├── Polynomial.hpp │ ├── Rational.hpp │ ├── Zn.hpp │ ├── bits.hpp │ ├── division.hpp │ ├── divisors.hpp │ ├── extendedGcd.hpp │ ├── gcd.hpp │ ├── lcm.hpp │ ├── linearSieve.hpp │ ├── numbers.hpp │ ├── phi.hpp │ ├── primes.hpp │ └── progression.hpp ├── parallel.hpp ├── random │ └── random.hpp ├── ranges │ ├── Range.hpp │ ├── fors.hpp │ ├── indices.hpp │ ├── pairwiseMerge.hpp │ ├── prefixSums.hpp │ ├── range_iterator_traits.hpp │ └── wrappers.hpp ├── strings │ ├── SuffixArray.hpp │ ├── hash │ │ ├── OverflowHasher.hpp │ │ ├── StringHash.hpp │ │ └── TwoIntsHasher.hpp │ └── prefixFunction.hpp ├── typeTraits │ ├── Disjunction.hpp │ ├── IsContainer.hpp │ ├── IsOneOf.hpp │ ├── IsSaneInteger.hpp │ └── enable_if_t.hpp └── updateMin.hpp └── tests ├── CoordinateMinimizer.cpp ├── DSU.cpp ├── Matrix.cpp ├── binpow.cpp ├── convolution.cpp ├── dataStructures ├── BitSet.cpp ├── MinQueue.cpp ├── NDArray.cpp ├── SparseTable.cpp ├── TreapMultiset.cpp └── segmentTree │ ├── BottomUpMaxSegmentTree.cpp │ ├── BottomUpMinSegmentTree.cpp │ └── TopDownSumSegmentTree.cpp ├── detectionIdiom.hpp ├── geometry ├── Point2D.cpp └── convexHull.cpp ├── graphs └── algorithms │ ├── dynamicConnectivityOffline.cpp │ └── findIndependentSetInBipartiteGraph.cpp ├── identity.cpp ├── make_vector.cpp ├── numbers ├── BigInteger.cpp ├── Zn.cpp ├── bits.cpp ├── division.cpp ├── divisors.cpp ├── extended_gcd.cpp ├── gcd.cpp ├── lcm.cpp ├── numbers.cpp └── primes.cpp ├── operator_size.hpp ├── parallel.cpp ├── ranges ├── indices.cpp ├── pairwiseMerge.cpp ├── prefixSums.cpp └── wrappers.cpp ├── strings ├── StringHash.cpp ├── SuffixArray.cpp └── prefixFunction.cpp ├── typeTraits ├── IsContainer.cpp └── IsSaneInteger.cpp └── updateMin.cpp /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++14 -Wall -Wextra -pedantic -Wformat=2") 2 | 3 | file(GLOB_RECURSE HEADERS "spcppl/*.hpp") 4 | 5 | add_library(spcppl INTERFACE) 6 | target_include_directories(spcppl INTERFACE .) 7 | target_sources(spcppl INTERFACE ${HEADERS}) 8 | 9 | file(GLOB_RECURSE TESTS "tests/*.?pp") 10 | add_executable(tests ${TESTS}) 11 | target_link_libraries(tests spcppl) 12 | 13 | add_subdirectory(gtest) 14 | target_link_libraries(tests gtest_main) 15 | target_compile_options(tests PRIVATE -Werror -std=c++2a) 16 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The code is distributed under WTFPL 2.0 2 | 3 | Note also: 4 | 5 | 1. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 6 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 7 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 8 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 9 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 10 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 11 | THE SOFTWARE. 12 | 13 | 2. It may be disallowed to use this code in certain competitions 14 | 15 | License text: 16 | 17 | DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE 18 | Version 2, December 2004 19 | 20 | Copyright (C) 2004 Sam Hocevar 21 | 22 | Everyone is permitted to copy and distribute verbatim or modified 23 | copies of this license document, and changing it is allowed as long 24 | as the name is changed. 25 | 26 | DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE 27 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 28 | 29 | 0. You just DO WHAT THE FUCK YOU WANT TO. 30 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Prewritten code library for programming contests 2 | -------------------------------------------------------------------------------- /gtest/include/gtest/gtest_prod.h: -------------------------------------------------------------------------------- 1 | // Copyright 2006, Google Inc. 2 | // All rights reserved. 3 | // 4 | // Redistribution and use in source and binary forms, with or without 5 | // modification, are permitted provided that the following conditions are 6 | // met: 7 | // 8 | // * Redistributions of source code must retain the above copyright 9 | // notice, this list of conditions and the following disclaimer. 10 | // * Redistributions in binary form must reproduce the above 11 | // copyright notice, this list of conditions and the following disclaimer 12 | // in the documentation and/or other materials provided with the 13 | // distribution. 14 | // * Neither the name of Google Inc. nor the names of its 15 | // contributors may be used to endorse or promote products derived from 16 | // this software without specific prior written permission. 17 | // 18 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | // 30 | // Author: wan@google.com (Zhanyong Wan) 31 | // 32 | // Google C++ Testing Framework definitions useful in production code. 33 | 34 | #ifndef GTEST_INCLUDE_GTEST_GTEST_PROD_H_ 35 | #define GTEST_INCLUDE_GTEST_GTEST_PROD_H_ 36 | 37 | // When you need to test the private or protected members of a class, 38 | // use the FRIEND_TEST macro to declare your tests as friends of the 39 | // class. For example: 40 | // 41 | // class MyClass { 42 | // private: 43 | // void MyMethod(); 44 | // FRIEND_TEST(MyClassTest, MyMethod); 45 | // }; 46 | // 47 | // class MyClassTest : public testing::Test { 48 | // // ... 49 | // }; 50 | // 51 | // TEST_F(MyClassTest, MyMethod) { 52 | // // Can call MyClass::MyMethod() here. 53 | // } 54 | 55 | #define FRIEND_TEST(test_case_name, test_name)\ 56 | friend class test_case_name##_##test_name##_Test 57 | 58 | #endif // GTEST_INCLUDE_GTEST_GTEST_PROD_H_ 59 | -------------------------------------------------------------------------------- /gtest/include/gtest/internal/custom/gtest-port.h: -------------------------------------------------------------------------------- 1 | // Copyright 2015, Google Inc. 2 | // All rights reserved. 3 | // 4 | // Redistribution and use in source and binary forms, with or without 5 | // modification, are permitted provided that the following conditions are 6 | // met: 7 | // 8 | // * Redistributions of source code must retain the above copyright 9 | // notice, this list of conditions and the following disclaimer. 10 | // * Redistributions in binary form must reproduce the above 11 | // copyright notice, this list of conditions and the following disclaimer 12 | // in the documentation and/or other materials provided with the 13 | // distribution. 14 | // * Neither the name of Google Inc. nor the names of its 15 | // contributors may be used to endorse or promote products derived from 16 | // this software without specific prior written permission. 17 | // 18 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | // 30 | // Injection point for custom user configurations. 31 | // The following macros can be defined: 32 | // 33 | // Flag related macros: 34 | // GTEST_FLAG(flag_name) 35 | // GTEST_USE_OWN_FLAGFILE_FLAG_ - Define to 0 when the system provides its 36 | // own flagfile flag parsing. 37 | // GTEST_DECLARE_bool_(name) 38 | // GTEST_DECLARE_int32_(name) 39 | // GTEST_DECLARE_string_(name) 40 | // GTEST_DEFINE_bool_(name, default_val, doc) 41 | // GTEST_DEFINE_int32_(name, default_val, doc) 42 | // GTEST_DEFINE_string_(name, default_val, doc) 43 | // 44 | // Test filtering: 45 | // GTEST_TEST_FILTER_ENV_VAR_ - The name of an environment variable that 46 | // will be used if --GTEST_FLAG(test_filter) 47 | // is not provided. 48 | // 49 | // Logging: 50 | // GTEST_LOG_(severity) 51 | // GTEST_CHECK_(condition) 52 | // Functions LogToStderr() and FlushInfoLog() have to be provided too. 53 | // 54 | // Threading: 55 | // GTEST_HAS_NOTIFICATION_ - Enabled if Notification is already provided. 56 | // GTEST_HAS_MUTEX_AND_THREAD_LOCAL_ - Enabled if Mutex and ThreadLocal are 57 | // already provided. 58 | // Must also provide GTEST_DECLARE_STATIC_MUTEX_(mutex) and 59 | // GTEST_DEFINE_STATIC_MUTEX_(mutex) 60 | // 61 | // GTEST_EXCLUSIVE_LOCK_REQUIRED_(locks) 62 | // GTEST_LOCK_EXCLUDED_(locks) 63 | // 64 | // ** Custom implementation starts here ** 65 | 66 | #ifndef GTEST_INCLUDE_GTEST_INTERNAL_CUSTOM_GTEST_PORT_H_ 67 | #define GTEST_INCLUDE_GTEST_INTERNAL_CUSTOM_GTEST_PORT_H_ 68 | 69 | #endif // GTEST_INCLUDE_GTEST_INTERNAL_CUSTOM_GTEST_PORT_H_ 70 | -------------------------------------------------------------------------------- /gtest/include/gtest/internal/custom/gtest-printers.h: -------------------------------------------------------------------------------- 1 | // Copyright 2015, Google Inc. 2 | // All rights reserved. 3 | // 4 | // Redistribution and use in source and binary forms, with or without 5 | // modification, are permitted provided that the following conditions are 6 | // met: 7 | // 8 | // * Redistributions of source code must retain the above copyright 9 | // notice, this list of conditions and the following disclaimer. 10 | // * Redistributions in binary form must reproduce the above 11 | // copyright notice, this list of conditions and the following disclaimer 12 | // in the documentation and/or other materials provided with the 13 | // distribution. 14 | // * Neither the name of Google Inc. nor the names of its 15 | // contributors may be used to endorse or promote products derived from 16 | // this software without specific prior written permission. 17 | // 18 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | // 30 | // This file provides an injection point for custom printers in a local 31 | // installation of gTest. 32 | // It will be included from gtest-printers.h and the overrides in this file 33 | // will be visible to everyone. 34 | // See documentation at gtest/gtest-printers.h for details on how to define a 35 | // custom printer. 36 | // 37 | // ** Custom implementation starts here ** 38 | 39 | #ifndef GTEST_INCLUDE_GTEST_INTERNAL_CUSTOM_GTEST_PRINTERS_H_ 40 | #define GTEST_INCLUDE_GTEST_INTERNAL_CUSTOM_GTEST_PRINTERS_H_ 41 | 42 | #endif // GTEST_INCLUDE_GTEST_INTERNAL_CUSTOM_GTEST_PRINTERS_H_ 43 | -------------------------------------------------------------------------------- /gtest/include/gtest/internal/custom/gtest.h: -------------------------------------------------------------------------------- 1 | // Copyright 2015, Google Inc. 2 | // All rights reserved. 3 | // 4 | // Redistribution and use in source and binary forms, with or without 5 | // modification, are permitted provided that the following conditions are 6 | // met: 7 | // 8 | // * Redistributions of source code must retain the above copyright 9 | // notice, this list of conditions and the following disclaimer. 10 | // * Redistributions in binary form must reproduce the above 11 | // copyright notice, this list of conditions and the following disclaimer 12 | // in the documentation and/or other materials provided with the 13 | // distribution. 14 | // * Neither the name of Google Inc. nor the names of its 15 | // contributors may be used to endorse or promote products derived from 16 | // this software without specific prior written permission. 17 | // 18 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | // 30 | // Injection point for custom user configurations. 31 | // The following macros can be defined: 32 | // 33 | // GTEST_OS_STACK_TRACE_GETTER_ - The name of an implementation of 34 | // OsStackTraceGetterInterface. 35 | // 36 | // ** Custom implementation starts here ** 37 | 38 | #ifndef GTEST_INCLUDE_GTEST_INTERNAL_CUSTOM_GTEST_H_ 39 | #define GTEST_INCLUDE_GTEST_INTERNAL_CUSTOM_GTEST_H_ 40 | 41 | #endif // GTEST_INCLUDE_GTEST_INTERNAL_CUSTOM_GTEST_H_ 42 | -------------------------------------------------------------------------------- /gtest/include/gtest/internal/gtest-port-arch.h: -------------------------------------------------------------------------------- 1 | // Copyright 2015, Google Inc. 2 | // All rights reserved. 3 | // 4 | // Redistribution and use in source and binary forms, with or without 5 | // modification, are permitted provided that the following conditions are 6 | // met: 7 | // 8 | // * Redistributions of source code must retain the above copyright 9 | // notice, this list of conditions and the following disclaimer. 10 | // * Redistributions in binary form must reproduce the above 11 | // copyright notice, this list of conditions and the following disclaimer 12 | // in the documentation and/or other materials provided with the 13 | // distribution. 14 | // * Neither the name of Google Inc. nor the names of its 15 | // contributors may be used to endorse or promote products derived from 16 | // this software without specific prior written permission. 17 | // 18 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | // 30 | // The Google C++ Testing Framework (Google Test) 31 | // 32 | // This header file defines the GTEST_OS_* macro. 33 | // It is separate from gtest-port.h so that custom/gtest-port.h can include it. 34 | 35 | #ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PORT_ARCH_H_ 36 | #define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PORT_ARCH_H_ 37 | 38 | // Determines the platform on which Google Test is compiled. 39 | #ifdef __CYGWIN__ 40 | # define GTEST_OS_CYGWIN 1 41 | #elif defined __SYMBIAN32__ 42 | # define GTEST_OS_SYMBIAN 1 43 | #elif defined _WIN32 44 | # define GTEST_OS_WINDOWS 1 45 | # ifdef _WIN32_WCE 46 | # define GTEST_OS_WINDOWS_MOBILE 1 47 | # elif defined(__MINGW__) || defined(__MINGW32__) 48 | # define GTEST_OS_WINDOWS_MINGW 1 49 | # elif defined(WINAPI_FAMILY) 50 | # include 51 | # if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) 52 | # define GTEST_OS_WINDOWS_DESKTOP 1 53 | # elif WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_PHONE_APP) 54 | # define GTEST_OS_WINDOWS_PHONE 1 55 | # elif WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP) 56 | # define GTEST_OS_WINDOWS_RT 1 57 | # else 58 | // WINAPI_FAMILY defined but no known partition matched. 59 | // Default to desktop. 60 | # define GTEST_OS_WINDOWS_DESKTOP 1 61 | # endif 62 | # else 63 | # define GTEST_OS_WINDOWS_DESKTOP 1 64 | # endif // _WIN32_WCE 65 | #elif defined __APPLE__ 66 | # define GTEST_OS_MAC 1 67 | # if TARGET_OS_IPHONE 68 | # define GTEST_OS_IOS 1 69 | # endif 70 | #elif defined __FreeBSD__ 71 | # define GTEST_OS_FREEBSD 1 72 | #elif defined __linux__ 73 | # define GTEST_OS_LINUX 1 74 | # if defined __ANDROID__ 75 | # define GTEST_OS_LINUX_ANDROID 1 76 | # endif 77 | #elif defined __MVS__ 78 | # define GTEST_OS_ZOS 1 79 | #elif defined(__sun) && defined(__SVR4) 80 | # define GTEST_OS_SOLARIS 1 81 | #elif defined(_AIX) 82 | # define GTEST_OS_AIX 1 83 | #elif defined(__hpux) 84 | # define GTEST_OS_HPUX 1 85 | #elif defined __native_client__ 86 | # define GTEST_OS_NACL 1 87 | #elif defined __OpenBSD__ 88 | # define GTEST_OS_OPENBSD 1 89 | #elif defined __QNX__ 90 | # define GTEST_OS_QNX 1 91 | #endif // __CYGWIN__ 92 | 93 | #endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PORT_ARCH_H_ 94 | -------------------------------------------------------------------------------- /gtest/src/gtest-all.cc: -------------------------------------------------------------------------------- 1 | // Copyright 2008, Google Inc. 2 | // All rights reserved. 3 | // 4 | // Redistribution and use in source and binary forms, with or without 5 | // modification, are permitted provided that the following conditions are 6 | // met: 7 | // 8 | // * Redistributions of source code must retain the above copyright 9 | // notice, this list of conditions and the following disclaimer. 10 | // * Redistributions in binary form must reproduce the above 11 | // copyright notice, this list of conditions and the following disclaimer 12 | // in the documentation and/or other materials provided with the 13 | // distribution. 14 | // * Neither the name of Google Inc. nor the names of its 15 | // contributors may be used to endorse or promote products derived from 16 | // this software without specific prior written permission. 17 | // 18 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | // 30 | // Author: mheule@google.com (Markus Heule) 31 | // 32 | // Google C++ Testing Framework (Google Test) 33 | // 34 | // Sometimes it's desirable to build Google Test by compiling a single file. 35 | // This file serves this purpose. 36 | 37 | // This line ensures that gtest.h can be compiled on its own, even 38 | // when it's fused. 39 | #include "gtest/gtest.h" 40 | 41 | // The following lines pull in the real gtest *.cc files. 42 | #include "src/gtest.cc" 43 | #include "src/gtest-death-test.cc" 44 | #include "src/gtest-filepath.cc" 45 | #include "src/gtest-port.cc" 46 | #include "src/gtest-printers.cc" 47 | #include "src/gtest-test-part.cc" 48 | #include "src/gtest-typed-test.cc" 49 | -------------------------------------------------------------------------------- /gtest/src/gtest-test-part.cc: -------------------------------------------------------------------------------- 1 | // Copyright 2008, Google Inc. 2 | // All rights reserved. 3 | // 4 | // Redistribution and use in source and binary forms, with or without 5 | // modification, are permitted provided that the following conditions are 6 | // met: 7 | // 8 | // * Redistributions of source code must retain the above copyright 9 | // notice, this list of conditions and the following disclaimer. 10 | // * Redistributions in binary form must reproduce the above 11 | // copyright notice, this list of conditions and the following disclaimer 12 | // in the documentation and/or other materials provided with the 13 | // distribution. 14 | // * Neither the name of Google Inc. nor the names of its 15 | // contributors may be used to endorse or promote products derived from 16 | // this software without specific prior written permission. 17 | // 18 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | // 30 | // Author: mheule@google.com (Markus Heule) 31 | // 32 | // The Google C++ Testing Framework (Google Test) 33 | 34 | #include "gtest/gtest-test-part.h" 35 | 36 | // Indicates that this translation unit is part of Google Test's 37 | // implementation. It must come before gtest-internal-inl.h is 38 | // included, or there will be a compiler error. This trick exists to 39 | // prevent the accidental inclusion of gtest-internal-inl.h in the 40 | // user's code. 41 | #define GTEST_IMPLEMENTATION_ 1 42 | #include "src/gtest-internal-inl.h" 43 | #undef GTEST_IMPLEMENTATION_ 44 | 45 | namespace testing { 46 | 47 | using internal::GetUnitTestImpl; 48 | 49 | // Gets the summary of the failure message by omitting the stack trace 50 | // in it. 51 | std::string TestPartResult::ExtractSummary(const char* message) { 52 | const char* const stack_trace = strstr(message, internal::kStackTraceMarker); 53 | return stack_trace == NULL ? message : 54 | std::string(message, stack_trace); 55 | } 56 | 57 | // Prints a TestPartResult object. 58 | std::ostream& operator<<(std::ostream& os, const TestPartResult& result) { 59 | return os 60 | << result.file_name() << ":" << result.line_number() << ": " 61 | << (result.type() == TestPartResult::kSuccess ? "Success" : 62 | result.type() == TestPartResult::kFatalFailure ? "Fatal failure" : 63 | "Non-fatal failure") << ":\n" 64 | << result.message() << std::endl; 65 | } 66 | 67 | // Appends a TestPartResult to the array. 68 | void TestPartResultArray::Append(const TestPartResult& result) { 69 | array_.push_back(result); 70 | } 71 | 72 | // Returns the TestPartResult at the given index (0-based). 73 | const TestPartResult& TestPartResultArray::GetTestPartResult(int index) const { 74 | if (index < 0 || index >= size()) { 75 | printf("\nInvalid index (%d) into TestPartResultArray.\n", index); 76 | internal::posix::Abort(); 77 | } 78 | 79 | return array_[index]; 80 | } 81 | 82 | // Returns the number of TestPartResult objects in the array. 83 | int TestPartResultArray::size() const { 84 | return static_cast(array_.size()); 85 | } 86 | 87 | namespace internal { 88 | 89 | HasNewFatalFailureHelper::HasNewFatalFailureHelper() 90 | : has_new_fatal_failure_(false), 91 | original_reporter_(GetUnitTestImpl()-> 92 | GetTestPartResultReporterForCurrentThread()) { 93 | GetUnitTestImpl()->SetTestPartResultReporterForCurrentThread(this); 94 | } 95 | 96 | HasNewFatalFailureHelper::~HasNewFatalFailureHelper() { 97 | GetUnitTestImpl()->SetTestPartResultReporterForCurrentThread( 98 | original_reporter_); 99 | } 100 | 101 | void HasNewFatalFailureHelper::ReportTestPartResult( 102 | const TestPartResult& result) { 103 | if (result.fatally_failed()) 104 | has_new_fatal_failure_ = true; 105 | original_reporter_->ReportTestPartResult(result); 106 | } 107 | 108 | } // namespace internal 109 | 110 | } // namespace testing 111 | -------------------------------------------------------------------------------- /gtest/src/gtest-typed-test.cc: -------------------------------------------------------------------------------- 1 | // Copyright 2008 Google Inc. 2 | // All Rights Reserved. 3 | // 4 | // Redistribution and use in source and binary forms, with or without 5 | // modification, are permitted provided that the following conditions are 6 | // met: 7 | // 8 | // * Redistributions of source code must retain the above copyright 9 | // notice, this list of conditions and the following disclaimer. 10 | // * Redistributions in binary form must reproduce the above 11 | // copyright notice, this list of conditions and the following disclaimer 12 | // in the documentation and/or other materials provided with the 13 | // distribution. 14 | // * Neither the name of Google Inc. nor the names of its 15 | // contributors may be used to endorse or promote products derived from 16 | // this software without specific prior written permission. 17 | // 18 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | // 30 | // Author: wan@google.com (Zhanyong Wan) 31 | 32 | #include "gtest/gtest-typed-test.h" 33 | #include "gtest/gtest.h" 34 | 35 | namespace testing { 36 | namespace internal { 37 | 38 | #if GTEST_HAS_TYPED_TEST_P 39 | 40 | // Skips to the first non-space char in str. Returns an empty string if str 41 | // contains only whitespace characters. 42 | static const char* SkipSpaces(const char* str) { 43 | while (IsSpace(*str)) 44 | str++; 45 | return str; 46 | } 47 | 48 | static std::vector SplitIntoTestNames(const char* src) { 49 | std::vector name_vec; 50 | src = SkipSpaces(src); 51 | for (; src != NULL; src = SkipComma(src)) { 52 | name_vec.push_back(StripTrailingSpaces(GetPrefixUntilComma(src))); 53 | } 54 | return name_vec; 55 | } 56 | 57 | // Verifies that registered_tests match the test names in 58 | // registered_tests_; returns registered_tests if successful, or 59 | // aborts the program otherwise. 60 | const char* TypedTestCasePState::VerifyRegisteredTestNames( 61 | const char* file, int line, const char* registered_tests) { 62 | typedef RegisteredTestsMap::const_iterator RegisteredTestIter; 63 | registered_ = true; 64 | 65 | std::vector name_vec = SplitIntoTestNames(registered_tests); 66 | 67 | Message errors; 68 | 69 | std::set tests; 70 | for (std::vector::const_iterator name_it = name_vec.begin(); 71 | name_it != name_vec.end(); ++name_it) { 72 | const std::string& name = *name_it; 73 | if (tests.count(name) != 0) { 74 | errors << "Test " << name << " is listed more than once.\n"; 75 | continue; 76 | } 77 | 78 | bool found = false; 79 | for (RegisteredTestIter it = registered_tests_.begin(); 80 | it != registered_tests_.end(); 81 | ++it) { 82 | if (name == it->first) { 83 | found = true; 84 | break; 85 | } 86 | } 87 | 88 | if (found) { 89 | tests.insert(name); 90 | } else { 91 | errors << "No test named " << name 92 | << " can be found in this test case.\n"; 93 | } 94 | } 95 | 96 | for (RegisteredTestIter it = registered_tests_.begin(); 97 | it != registered_tests_.end(); 98 | ++it) { 99 | if (tests.count(it->first) == 0) { 100 | errors << "You forgot to list test " << it->first << ".\n"; 101 | } 102 | } 103 | 104 | const std::string& errors_str = errors.GetString(); 105 | if (errors_str != "") { 106 | fprintf(stderr, "%s %s", FormatFileLocation(file, line).c_str(), 107 | errors_str.c_str()); 108 | fflush(stderr); 109 | posix::Abort(); 110 | } 111 | 112 | return registered_tests; 113 | } 114 | 115 | #endif // GTEST_HAS_TYPED_TEST_P 116 | 117 | } // namespace internal 118 | } // namespace testing 119 | -------------------------------------------------------------------------------- /gtest/src/gtest_main.cc: -------------------------------------------------------------------------------- 1 | // Copyright 2006, Google Inc. 2 | // All rights reserved. 3 | // 4 | // Redistribution and use in source and binary forms, with or without 5 | // modification, are permitted provided that the following conditions are 6 | // met: 7 | // 8 | // * Redistributions of source code must retain the above copyright 9 | // notice, this list of conditions and the following disclaimer. 10 | // * Redistributions in binary form must reproduce the above 11 | // copyright notice, this list of conditions and the following disclaimer 12 | // in the documentation and/or other materials provided with the 13 | // distribution. 14 | // * Neither the name of Google Inc. nor the names of its 15 | // contributors may be used to endorse or promote products derived from 16 | // this software without specific prior written permission. 17 | // 18 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | 30 | #include 31 | 32 | #include "gtest/gtest.h" 33 | 34 | GTEST_API_ int main(int argc, char **argv) { 35 | printf("Running main() from gtest_main.cc\n"); 36 | testing::InitGoogleTest(&argc, argv); 37 | return RUN_ALL_TESTS(); 38 | } 39 | -------------------------------------------------------------------------------- /spcppl/Bool.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | struct Bool { 4 | Bool() = default; 5 | 6 | /* implicit */ Bool(bool value): value(value) { 7 | 8 | } 9 | 10 | operator bool() const { 11 | return value; 12 | } 13 | 14 | private: 15 | bool value; 16 | }; 17 | -------------------------------------------------------------------------------- /spcppl/CoordinateMinimizer.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include "assert.hpp" 5 | #include "ranges/wrappers.hpp" 6 | 7 | template 8 | class CoordinateMinimizer { 9 | public: 10 | CoordinateMinimizer() { 11 | #ifdef SPCPPL_DEBUG 12 | addingFinished = false; 13 | #endif 14 | } 15 | 16 | template 17 | explicit CoordinateMinimizer(const R& range): values(range.begin(), range.end()) { 18 | finalize(); 19 | } 20 | 21 | void finalize() { 22 | sort(values); 23 | values.erase(std::unique(values.begin(), values.end()), values.end()); 24 | 25 | #ifdef SPCPPL_DEBUG 26 | addingFinished = true; 27 | #endif 28 | } 29 | 30 | void add(const T& t) { 31 | SPCPPL_ASSERT(!addingFinished); 32 | values.push_back(t); 33 | } 34 | 35 | void add(T&& t) { 36 | SPCPPL_ASSERT(!addingFinished); 37 | values.push_back(std::move(t)); 38 | } 39 | 40 | std::size_t find(const T& t) { 41 | SPCPPL_ASSERT(addingFinished); 42 | auto iterator = lower_bound(values, t); 43 | SPCPPL_ASSERT(iterator != values.end() && *iterator == t); 44 | return iterator - values.begin(); 45 | } 46 | 47 | std::size_t size() { 48 | SPCPPL_ASSERT(addingFinished); 49 | return values.size(); 50 | }; 51 | 52 | private: 53 | std::vector values; 54 | #ifdef SPCPPL_DEBUG 55 | bool addingFinished; 56 | #endif 57 | }; 58 | -------------------------------------------------------------------------------- /spcppl/DSU.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include "assert.hpp" 6 | 7 | class DSU { 8 | public: 9 | explicit DSU(std::size_t n): dsu(n) { 10 | for (std::size_t i = 0; i < n; ++i) { 11 | dsu[i] = i; 12 | } 13 | } 14 | 15 | std::size_t getSet(std::size_t v) { 16 | SPCPPL_ASSERT(v < dsu.size()); 17 | if (v == dsu[v]) { 18 | return v; 19 | } 20 | return dsu[v] = getSet(dsu[v]); 21 | } 22 | 23 | bool unite(std::size_t u, std::size_t v) { 24 | SPCPPL_ASSERT(u < dsu.size()); 25 | SPCPPL_ASSERT(v < dsu.size()); 26 | u = getSet(u); 27 | v = getSet(v); 28 | if (u == v) { 29 | return false; 30 | } else { 31 | dsu[v] = u; 32 | return true; 33 | } 34 | } 35 | 36 | std::size_t components() const { 37 | std::size_t count = 0; 38 | for (std::size_t i = 0; i < dsu.size(); ++i) { 39 | if (dsu[i] == i) { 40 | ++count; 41 | } 42 | } 43 | return count; 44 | } 45 | 46 | private: 47 | std::vector dsu; 48 | }; 49 | -------------------------------------------------------------------------------- /spcppl/Matrix.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include "assert.hpp" 6 | #include "matrixMultiplication.hpp" 7 | #include "identity.hpp" 8 | #include "make_vector.hpp" 9 | 10 | template 11 | class Matrix { 12 | public: 13 | explicit Matrix(const T& value = T()): value({rows(), columns()}, value) { 14 | 15 | } 16 | 17 | std::size_t rows() const { 18 | return N::value; 19 | } 20 | 21 | std::size_t columns() const { 22 | return M::value; 23 | } 24 | 25 | auto operator[](std::size_t index) { 26 | SPCPPL_ASSERT(index < rows()); 27 | return value[index]; 28 | } 29 | 30 | auto operator[](std::size_t index) const { 31 | SPCPPL_ASSERT(index < rows()); 32 | return value[index]; 33 | } 34 | 35 | Matrix& operator*=(const Matrix& rhs) { 36 | return *this = *this * rhs; 37 | } 38 | 39 | Matrix& operator+=(const Matrix& rhs) { 40 | for (std::size_t i = 0; i < rows(); ++i) { 41 | for (std::size_t j = 0; j < columns(); ++j) { 42 | value[i][j] += rhs.value[i][j]; 43 | } 44 | } 45 | return *this; 46 | } 47 | 48 | Matrix operator-() const { 49 | Matrix copy = *this; 50 | for (int i = 0; i < rows(); ++i) { 51 | for (int j = 0; j < columns(); ++j) { 52 | copy[i][j] = -copy[i][j]; 53 | } 54 | } 55 | return copy; 56 | } 57 | 58 | Matrix operator-=(const Matrix& rhs) { 59 | return *this += -rhs; 60 | } 61 | 62 | Matrix transposed() const { 63 | Matrix res; 64 | for (std::size_t i = 0; i < rows(); ++i) { 65 | for (std::size_t j = 0; j < columns(); ++j) { 66 | res[j][i] = value[i][j]; 67 | } 68 | } 69 | return res; 70 | } 71 | 72 | private: 73 | NDArray value; 74 | 75 | template 76 | friend bool operator==(const Matrix& lhs, const Matrix& rhs); 77 | }; 78 | 79 | template 80 | bool operator==(const Matrix& lhs, const Matrix& rhs) { 81 | return lhs.value == rhs.value; 82 | } 83 | 84 | template 85 | Matrix operator*(const Matrix& lhs, const Matrix& rhs) { 86 | Matrix res; 87 | impl::matrixMultiplication(lhs, rhs, res); 88 | return res; 89 | } 90 | 91 | template 92 | Matrix operator+(Matrix lhs, const Matrix& rhs) { 93 | Matrix copy = std::move(lhs); 94 | return copy += rhs; 95 | } 96 | 97 | template 98 | Matrix operator-(Matrix lhs, const Matrix& rhs) { 99 | Matrix copy = std::move(lhs); 100 | return copy -= rhs; 101 | } 102 | 103 | template 104 | struct IdentityHelper> { 105 | static Matrix identity() { 106 | Matrix res; 107 | for (std::size_t i = 0; i < N::value; ++i) { 108 | res[i][i] = ::identity(); 109 | } 110 | return res; 111 | } 112 | }; 113 | 114 | template 115 | using FixedSizeMatrix = Matrix, std::integral_constant>; 116 | -------------------------------------------------------------------------------- /spcppl/assert.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | #ifndef SPCPPL_ASSERT 7 | #ifdef SPCPPL_DEBUG 8 | #define SPCPPL_ASSERT(condition) \ 9 | if(!(condition)) { \ 10 | throw std::runtime_error(std::string() + #condition + " in line " + std::to_string(__LINE__) + " in " + __PRETTY_FUNCTION__); \ 11 | } 12 | #else 13 | #define SPCPPL_ASSERT(condition) 14 | #endif 15 | #endif 16 | -------------------------------------------------------------------------------- /spcppl/asserts.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | #ifndef SPCPPL_IGNORE_ASSERTS 7 | 8 | void assert_re(bool value) { 9 | if (!value) { 10 | std::exit(1); 11 | } 12 | } 13 | 14 | void assert_tl(bool value) { 15 | if (!value) { 16 | while (true) { 17 | } 18 | } 19 | } 20 | 21 | void assert_wa(bool value) { 22 | if (!value) { 23 | std::cout << "karamba"; 24 | std::exit(0); 25 | } 26 | } 27 | 28 | #else 29 | #define assert_re(x) 30 | #define assert_tl(x) 31 | #define assert_wa(x) 32 | #endif 33 | -------------------------------------------------------------------------------- /spcppl/binpow.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "identity.hpp" 4 | #include "assert.hpp" 5 | 6 | template 7 | T binpow(T base, long long power) { 8 | SPCPPL_ASSERT(power >= 0); 9 | T result = identity(); 10 | while (power > 0) { 11 | if (power & 1) { 12 | result *= base; 13 | } 14 | power >>= 1; 15 | base *= base; 16 | } 17 | return result; 18 | } 19 | -------------------------------------------------------------------------------- /spcppl/convolution.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include "assert.hpp" 5 | #include "ranges/fors.hpp" 6 | #include "numbers/bits.hpp" 7 | 8 | template 9 | std::vector submasksSums(std::vector data) { 10 | SPCPPL_ASSERT(isPowerOf2(data.size())); 11 | 12 | for (std::size_t power = 1; power < data.size(); power *= 2) { 13 | for (std::size_t mask: range(data.size())) { 14 | if (mask & power) { 15 | data[mask] += data[mask ^ power]; 16 | } 17 | } 18 | } 19 | return data; 20 | } 21 | -------------------------------------------------------------------------------- /spcppl/dataStructures/BitSet.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | template 13 | class BitSet { 14 | public: 15 | BitSet(): v(getUnderlyingSize(size())) { 16 | } 17 | 18 | template 19 | static BitSet fromIndices(const Collection& collection) { 20 | BitSet result; 21 | for (std::size_t index: collection) { 22 | result.set(index); 23 | } 24 | return result; 25 | } 26 | 27 | static BitSet fromIndices(std::initializer_list collection) { 28 | return fromIndices>(collection); 29 | } 30 | 31 | bool get(std::size_t index) const { 32 | SPCPPL_ASSERT(index < size()); 33 | return static_cast((v[index >> 5] >> (index & 31)) & 1); 34 | } 35 | 36 | void set(std::size_t index, bool value) { 37 | if (value) { 38 | set(index); 39 | } else { 40 | clear(index); 41 | } 42 | } 43 | 44 | void set(std::size_t index) { 45 | SPCPPL_ASSERT(index < size()); 46 | v[index >> 5] |= 1U << (index & 31); 47 | } 48 | 49 | void clear(std::size_t index) { 50 | SPCPPL_ASSERT(index < size()); 51 | v[index >> 5] &= ~(1U << (index & 31)); 52 | } 53 | 54 | void flip(std::size_t index) { 55 | SPCPPL_ASSERT(index < size()); 56 | v[index >> 5] ^= 1U << (index & 31); 57 | } 58 | 59 | std::size_t firstBitFrom(std::size_t index) const { 60 | if (index == size()) { 61 | return index; 62 | } 63 | uint32_t maskFromIndex = ~((static_cast(1) << (index & 31)) - 1); 64 | auto firstBlock = v[index >> 5]; 65 | uint32_t value = maskFromIndex & firstBlock; 66 | if (value != 0) { 67 | return (index & ~static_cast(31)) + countTrailingZeros(value); 68 | } 69 | auto it = std::find_if(v.begin() + (index >> 5) + 1, v.end(), [](auto x) { 70 | return x != 0; 71 | }); 72 | if (it == v.end()) { 73 | return size(); 74 | } 75 | return (it - v.begin()) * 32 + countTrailingZeros(*it); 76 | } 77 | 78 | std::size_t firstBitAfter(std::size_t index) const { 79 | return firstBitFrom(index + 1); 80 | } 81 | 82 | std::size_t count() const { 83 | std::size_t result = 0; 84 | for (auto block: v) { 85 | result += __builtin_popcount(block); 86 | } 87 | return result; 88 | } 89 | 90 | BitSet& operator|=(const BitSet& rhs) { 91 | for (auto i: range(v.size())) { 92 | v[i] |= rhs.v[i]; 93 | } 94 | return *this; 95 | } 96 | 97 | BitSet& operator&=(const BitSet& rhs) { 98 | for (auto i: range(v.size())) { 99 | v[i] &= rhs.v[i]; 100 | } 101 | return *this; 102 | } 103 | 104 | BitSet& operator^=(const BitSet& rhs) { 105 | for (auto i: range(v.size())) { 106 | v[i] ^= rhs.v[i]; 107 | } 108 | return *this; 109 | } 110 | 111 | BitSet operator~() const& { 112 | auto copy = *this; 113 | copy.invert(); 114 | return copy; 115 | } 116 | 117 | BitSet operator~() && { 118 | invert(); 119 | return *this; 120 | } 121 | 122 | bool empty() const { 123 | for (uint32_t number: v) { 124 | if (number != 0) { 125 | return false; 126 | } 127 | } 128 | return true; 129 | } 130 | 131 | std::size_t leastBit() const { 132 | for (std::size_t i: range(v.size())) { 133 | if (v[i] != 0) { 134 | return i * 32 + leastSignificantBit(v[i]); 135 | } 136 | } 137 | return size(); 138 | } 139 | 140 | BitSet& operator<<=(std::size_t rhs) { 141 | SPCPPL_ASSERT(rhs <= size()); 142 | std::size_t bigShifts = rhs >> 5; 143 | std::memmove(&v[bigShifts], &v[0], (v.size() - bigShifts) * sizeof(int32_t)); 144 | std::memset(&v[0], 0, bigShifts * sizeof(int32_t)); 145 | rhs &= 31; 146 | uint32_t add = 0; 147 | if (rhs != 0) { 148 | for (uint32_t& element: v) { 149 | uint32_t next = (element >> (32 - rhs)); 150 | element <<= rhs; 151 | element ^= add; 152 | add = next; 153 | } 154 | } 155 | std::size_t lastBits = size() & 31; 156 | if (lastBits > 0) { 157 | v.back() &= (1 << lastBits) - 1; 158 | } 159 | return *this; 160 | } 161 | 162 | BitSet& operator>>=(std::size_t rhs) { 163 | SPCPPL_ASSERT(rhs <= size()); 164 | std::size_t bigShifts = rhs >> 5; 165 | std::memmove(&v[0], &v[bigShifts], (v.size() - bigShifts) * sizeof(int32_t)); 166 | std::memset(&v[0] + v.size() - bigShifts, 0, bigShifts * sizeof(int32_t)); 167 | rhs &= 31; 168 | int32_t add = 0; 169 | if (rhs != 0) { 170 | for (std::size_t i: downrange(v.size())) { 171 | uint32_t next = (v[i] << (32 - rhs)); 172 | v[i] >>= rhs; 173 | v[i] ^= add; 174 | add = next; 175 | } 176 | } 177 | return *this; 178 | } 179 | 180 | std::size_t size() const { 181 | return N::value; 182 | } 183 | 184 | private: 185 | BitSet& invert() { 186 | for (auto& block: v) { 187 | block = ~block; 188 | } 189 | std::size_t lastBits = size() & 31; 190 | if (size() != 0) { 191 | v.back() &= (1 << lastBits) - 1; 192 | } 193 | return *this; 194 | } 195 | 196 | static std::size_t countTrailingZeros(uint32_t value) { 197 | return __builtin_ctz(value); 198 | } 199 | 200 | static std::size_t getUnderlyingSize(std::size_t size) { 201 | return (size + 31) >> 5; 202 | } 203 | 204 | std::vector v; 205 | 206 | template 207 | friend bool operator==(const BitSet& a, const BitSet& b); 208 | 209 | template 210 | friend std::ostream& operator<<(std::ostream& stream, const BitSet& b); 211 | }; 212 | 213 | template 214 | BitSet operator|(const BitSet& a, const BitSet& b) { 215 | BitSet copy = a; 216 | return copy |= b; 217 | } 218 | 219 | template 220 | BitSet operator&(const BitSet& a, const BitSet& b) { 221 | BitSet copy = a; 222 | return copy &= b; 223 | } 224 | 225 | template 226 | BitSet operator^(const BitSet& a, const BitSet& b) { 227 | BitSet copy = a; 228 | return copy ^= b; 229 | } 230 | 231 | template 232 | BitSet operator<<(const BitSet& a, std::size_t b) { 233 | BitSet copy = a; 234 | return copy <<= b; 235 | } 236 | 237 | template 238 | BitSet operator>>(const BitSet& a, std::size_t b) { 239 | BitSet copy = a; 240 | return copy >>= b; 241 | } 242 | 243 | template 244 | bool operator==(const BitSet& a, const BitSet& b) { 245 | return a.v == b.v; 246 | } 247 | 248 | template 249 | bool operator!=(const BitSet& a, const BitSet& b) { 250 | return !(a == b); 251 | } 252 | 253 | template 254 | std::ostream& operator<<(std::ostream& stream, const BitSet& b) { 255 | for (std::size_t index: range(b.size())) { 256 | stream << (b.get(index) ? '1' : '0'); 257 | } 258 | return stream; 259 | } 260 | -------------------------------------------------------------------------------- /spcppl/dataStructures/MinQueue.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | template > 9 | class MinQueue { 10 | public: 11 | explicit MinQueue(Compare compare = Compare()): size_(0), compare(compare) { 12 | } 13 | 14 | void push(const T& value) { 15 | push_impl(value); 16 | } 17 | 18 | void push(T&& value) { 19 | push_impl(std::move(value)); 20 | } 21 | 22 | void pop() { 23 | SPCPPL_ASSERT(!queue.empty()); 24 | if (--queue.front().second == 0) { 25 | queue.pop_front(); 26 | } 27 | --size_; 28 | } 29 | 30 | std::size_t size() const { 31 | return size_; 32 | } 33 | 34 | const T& getMinimum() const { 35 | SPCPPL_ASSERT(!queue.empty()); 36 | return queue.front().first; 37 | } 38 | 39 | private: 40 | template 41 | void push_impl(U&& value) { 42 | static_assert(std::is_same::value || std::is_same::value, ""); 43 | size_t elementsWithFixedMin = 1; 44 | while (!queue.empty() && !compare(queue.back().first, value)) { 45 | elementsWithFixedMin += queue.back().second; 46 | queue.pop_back(); 47 | } 48 | queue.emplace_back(std::forward(value), elementsWithFixedMin); 49 | ++size_; 50 | } 51 | std::size_t size_; 52 | std::deque> queue; 53 | Compare compare; 54 | }; 55 | -------------------------------------------------------------------------------- /spcppl/dataStructures/NDArray.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | template 12 | class NDArrayView { 13 | public: 14 | using Ref = std::conditional_t>; 15 | 16 | Ref operator[] (std::size_t index) const { 17 | return get_element_impl(index); 18 | } 19 | 20 | Ref front() const { 21 | return get_at_index(0); 22 | } 23 | 24 | Ref back() const { 25 | if (suffixSizes[0] == 0) { 26 | return front(); 27 | } 28 | return get_at_index(suffixSizes[0] - (depth == 1 ? 1 : suffixSizes[1])); 29 | } 30 | 31 | operator NDArrayView() const { 32 | return NDArrayView(elements, suffixSizes); 33 | } 34 | NDArrayView(NDArrayView&&) = default; 35 | NDArrayView& operator= (const NDArrayView&) = delete; 36 | NDArrayView&& operator= (NDArrayView&&) = delete; 37 | 38 | private: 39 | template * = nullptr> 40 | T& get_element_impl(std::size_t index) const { 41 | return elements[index]; 42 | } 43 | 44 | template * = nullptr> 45 | NDArrayView get_element_impl(std::size_t index) const { 46 | return NDArrayView(elements + suffixSizes[1] * index, suffixSizes + 1); 47 | } 48 | 49 | template * = nullptr> 50 | T& get_at_index(std::size_t index) const { 51 | return elements[index]; 52 | } 53 | 54 | template * = nullptr> 55 | NDArrayView get_at_index(std::size_t index) const { 56 | return NDArrayView(elements + index, suffixSizes + 1); 57 | } 58 | 59 | NDArrayView(T* elements, const std::size_t* suffixSizes): 60 | elements(elements), 61 | suffixSizes(suffixSizes) { 62 | } 63 | T* elements; 64 | const std::size_t* suffixSizes; 65 | 66 | template 67 | friend class NDArray; 68 | 69 | template 70 | friend class NDArrayView; 71 | 72 | template 73 | friend void assignView(NDArrayView lhs, NDArrayView rhs); 74 | }; 75 | 76 | template 77 | void assignView(NDArrayView lhs, NDArrayView rhs) { 78 | SPCPPL_ASSERT(lhs.suffixSizes[0] == rhs.suffixSizes[0]); 79 | std::copy(rhs.elements, rhs.elements + lhs.suffixSizes[0], lhs.elements); 80 | }; 81 | 82 | template 83 | bool operator==(const NDArrayView&, const NDArrayView&) = delete; 84 | 85 | template 86 | bool operator!=(const NDArrayView&, const NDArrayView&) = delete; 87 | 88 | template 89 | using NDArrayConstView = NDArrayView; 90 | 91 | template 92 | class NDArray { 93 | public: 94 | using Ref = typename NDArrayView::Ref; 95 | using ConstRef = typename NDArrayView::Ref; 96 | 97 | NDArray(const std::array& sizes): 98 | suffixSizes(suffixProducts(sizes)), 99 | elements(suffixSizes[0]) { 100 | } 101 | 102 | NDArray(const std::array& sizes, const T& t): 103 | suffixSizes(suffixProducts(sizes)), 104 | elements(suffixSizes[0], t) { 105 | } 106 | 107 | Ref operator[] (std::size_t index) { 108 | return static_cast>(*this)[index]; 109 | } 110 | 111 | ConstRef operator[] (std::size_t index) const { 112 | return static_cast>(*this)[index]; 113 | } 114 | 115 | operator NDArrayView() { 116 | return NDArrayView(elements.data(), suffixSizes.data()); 117 | } 118 | 119 | operator NDArrayConstView() const { 120 | return NDArrayConstView(elements.data(), suffixSizes.data()); 121 | } 122 | 123 | Ref front() { 124 | return static_cast>(*this).front(); 125 | } 126 | 127 | ConstRef front() const { 128 | return static_cast>(*this).front(); 129 | } 130 | 131 | Ref back() { 132 | return static_cast>(*this).back(); 133 | } 134 | 135 | ConstRef back() const { 136 | return static_cast>(*this).back(); 137 | } 138 | private: 139 | static std::array suffixProducts(const std::array& sizes) { 140 | std::array result; 141 | std::size_t last = 1; 142 | for (std::size_t index: downrange(depth)) { 143 | last *= sizes[index]; 144 | result[index] = last; 145 | } 146 | return result; 147 | } 148 | std::array suffixSizes; 149 | std::vector elements; 150 | 151 | 152 | template 153 | friend bool operator==(const NDArray& lhs, const NDArray& rhs); 154 | }; 155 | 156 | template 157 | NDArray makeArray(Args... sizes) { 158 | return NDArray( 159 | std::array{{ 160 | static_cast(sizes)... 161 | }} 162 | ); 163 | } 164 | 165 | template 166 | NDArray makeFilledArray(const T& value, Args... sizes) { 167 | return NDArray( 168 | std::array{{ 169 | static_cast(sizes)... 170 | }}, 171 | value 172 | ); 173 | } 174 | 175 | template 176 | bool operator==(const NDArray& lhs, const NDArray& rhs) { 177 | SPCPPL_ASSERT(lhs.suffixSizes == rhs.suffixSizes); 178 | return lhs.elements == rhs.elements; 179 | } 180 | 181 | template 182 | bool operator!=(const NDArray& lhs, const NDArray& rhs) { 183 | return !(lhs == rhs); 184 | } 185 | -------------------------------------------------------------------------------- /spcppl/dataStructures/SparseTable.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | template 8 | class SparseTable { 9 | public: 10 | explicit SparseTable(std::vector elements, const Operation& operation = Operation(), const T& neutralValue = T()): 11 | operation(operation), neutralValue(neutralValue) { 12 | std::size_t n = elements.size(); 13 | logarithms.resize(n + 1); 14 | for (std::size_t i = 2; i < logarithms.size(); ++i) { 15 | logarithms[i] = logarithms[i - 1]; 16 | if (isPowerOf2(i)) { 17 | ++logarithms[i]; 18 | } 19 | } 20 | 21 | table.push_back(std::move(elements)); 22 | table.resize(logarithms[n] + 1, std::vector(n)); 23 | 24 | for (auto i: range(static_cast(1), table.size())) { 25 | for (std::size_t j = 0; j + (1 << i) <= n; ++j) { 26 | table[i][j] = this->operation(table[i - 1][j], table[i - 1][j + (1 << (i - 1))]); 27 | } 28 | } 29 | } 30 | 31 | T getResult(std::size_t l, std::size_t r) const { 32 | SPCPPL_ASSERT(l <= r && r <= table[0].size()); 33 | if (l == r) { 34 | return neutralValue; 35 | } 36 | auto log = logarithms[r - l]; 37 | SPCPPL_ASSERT((1 << log) <= r - l); 38 | SPCPPL_ASSERT((1 << (log + 1)) >= r - l); 39 | return operation(table[log][l], table[log][r - (1 << log)]); 40 | } 41 | private: 42 | std::vector logarithms; 43 | std::vector> table; 44 | Operation operation; 45 | T neutralValue; 46 | }; 47 | -------------------------------------------------------------------------------- /spcppl/dataStructures/TreapMultiset.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | template 8 | class TreapMultiset { 9 | private: 10 | struct NodeStruct { 11 | T value; 12 | std::size_t count; 13 | NodeStruct* l; 14 | NodeStruct* r; 15 | int32_t priority; 16 | 17 | template 18 | explicit NodeStruct(Args&&... args): 19 | value(std::forward(args)...), 20 | count(1), 21 | l(nullptr), 22 | r(nullptr), 23 | priority(randomInteger()) { 24 | 25 | } 26 | 27 | void push() { 28 | 29 | } 30 | 31 | void recalc() { 32 | count = 1 + cnt(l) + cnt(r); 33 | } 34 | }; 35 | using Node = NodeStruct*; 36 | 37 | static std::size_t cnt(Node v) { 38 | if (!v) 39 | return 0; 40 | return v->count; 41 | } 42 | 43 | Node merge(Node l, Node r) { 44 | if (!l) { 45 | return r; 46 | } 47 | if (!r) { 48 | return l; 49 | } 50 | if (l->priority < r->priority) { 51 | l->push(); 52 | l->r = merge(l->r, r); 53 | l->recalc(); 54 | return l; 55 | } 56 | else { 57 | r->push(); 58 | r->l = merge(l, r->l); 59 | r->recalc(); 60 | return r; 61 | } 62 | } 63 | 64 | void clear(Node v) { 65 | if (v) { 66 | clear(v->l); 67 | clear(v->r); 68 | } 69 | delete v; 70 | } 71 | 72 | void splitByIndex(Node v, std::size_t index, Node& l, Node& r) { 73 | l = nullptr; 74 | r = nullptr; 75 | if (!v) { 76 | return; 77 | } 78 | v->push(); 79 | if (cnt(v->l) < index) { 80 | l = v; 81 | splitByIndex(l->r, index - cnt(v->l) - 1, l->r, r); 82 | l->recalc(); 83 | } 84 | else { 85 | r = v; 86 | splitByIndex(r->l, index, l, r->l); 87 | r->recalc(); 88 | } 89 | } 90 | 91 | void splitByValue(Node v, const T& value, Node& l, Node& r) { 92 | l = nullptr; 93 | r = nullptr; 94 | if (!v) { 95 | return; 96 | } 97 | v->push(); 98 | if (v->value < value) { 99 | l = v; 100 | splitByValue(l->r, value, l->r, r); 101 | l->recalc(); 102 | } 103 | else { 104 | r = v; 105 | splitByValue(r->l, value, l, r->l); 106 | r->recalc(); 107 | } 108 | } 109 | 110 | void insertNode(Node newNode) { 111 | Node l = nullptr; 112 | Node r = nullptr; 113 | splitByValue(root, newNode->value, l, r); 114 | root = merge(merge(l, newNode), r); 115 | } 116 | 117 | public: 118 | TreapMultiset(): root(nullptr) { 119 | } 120 | 121 | std::size_t size() const { 122 | return cnt(root); 123 | } 124 | 125 | template 126 | void emplace(Args&&... args) { 127 | insertNode(new NodeStruct(std::forward(args)...)); 128 | } 129 | 130 | void insert(const T& value) { 131 | insertNode(new NodeStruct(value)); 132 | } 133 | 134 | void insert(T&& value) { 135 | insertNode(new NodeStruct(std::move(value))); 136 | } 137 | 138 | void erase_one(const T& value) { 139 | Node l = nullptr; 140 | Node m = nullptr; 141 | Node r = nullptr; 142 | splitByValue(root, value, l, r); 143 | splitByIndex(r, 1, m, r); 144 | SPCPPL_ASSERT(m->value == value); 145 | delete m; 146 | root = merge(l, r); 147 | } 148 | 149 | const T* find(const T& value) { 150 | const T* result = lower_bound(value); 151 | if (result == nullptr || value < *result) { 152 | return result; 153 | } else { 154 | return false; 155 | } 156 | } 157 | 158 | // todo(performance): rewrite without split/merge 159 | const T* lower_bound(const T& value) { 160 | Node l = nullptr; 161 | Node m = nullptr; 162 | Node r = nullptr; 163 | splitByValue(root, value, l, r); 164 | if (r == nullptr) { 165 | root = l; 166 | return nullptr; 167 | } 168 | splitByIndex(r, 1, m, r); 169 | SPCPPL_ASSERT(m != nullptr); 170 | root = merge(merge(l, m), r); 171 | return &m->value; 172 | } 173 | 174 | // todo(performance): rewrite without split/merge 175 | const T& operator [](std::size_t index) { 176 | Node l = nullptr; 177 | Node m = nullptr; 178 | Node r = nullptr; 179 | splitByIndex(root, index, l, r); 180 | splitByIndex(r, 1, m, r); 181 | SPCPPL_ASSERT(m != nullptr); 182 | root = merge(merge(l, m), r); 183 | return m->value; 184 | } 185 | 186 | void clear() { 187 | clear(root); 188 | } 189 | 190 | private: 191 | Node root; 192 | }; 193 | -------------------------------------------------------------------------------- /spcppl/dataStructures/segmentTree/BottomUpMaxSegmentTree.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | template 8 | class BottomUpMaxSegmentTree: public BottomUpSegmentTree { 9 | public: 10 | template 11 | explicit BottomUpMaxSegmentTree( 12 | const R& range, 13 | const T& infinity = NegativeInfinity()() 14 | ): BottomUpSegmentTree(range, infinity) { 15 | } 16 | 17 | void updateMaximum(std::size_t index, const T& value) { 18 | return this->update(index, [&value, this](T& element) { 19 | element = this->merge(element, value); 20 | }); 21 | } 22 | 23 | std::size_t getFirstMaximum() const { 24 | return this->descend([](const T& v, const T& l, const T&) { 25 | return v == l; 26 | }); 27 | } 28 | }; 29 | -------------------------------------------------------------------------------- /spcppl/dataStructures/segmentTree/BottomUpMinSegmentTree.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include "BottomUpSegmentTree.hpp" 7 | #include 8 | #include 9 | 10 | template 11 | class BottomUpMinSegmentTree: public BottomUpSegmentTree { 12 | public: 13 | template 14 | explicit BottomUpMinSegmentTree( 15 | const R& range, 16 | const T& infinity = PositiveInfinity()() 17 | ): BottomUpSegmentTree(range, infinity) { 18 | } 19 | 20 | void updateMinimum(std::size_t index, const T& value) { 21 | return this->update(index, [&value, this](T& element) { 22 | element = this->merge(element, value); 23 | }); 24 | } 25 | 26 | std::size_t getFirstMinimum() const { 27 | return this->descend([](const T& v, const T& l, const T&) { 28 | return v == l; 29 | }); 30 | } 31 | }; 32 | -------------------------------------------------------------------------------- /spcppl/dataStructures/segmentTree/BottomUpSegmentTree.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include "SegementTreeBase.hpp" 5 | 6 | template 7 | class BottomUpSegmentTree: protected SegmentTreeBase { 8 | using Base = SegmentTreeBase; 9 | 10 | public: 11 | template 12 | explicit BottomUpSegmentTree(const R& range, const T& defaultValue = T(), const Merge& merge = Merge()): 13 | SegmentTreeBase(range, defaultValue, merge) { 14 | 15 | } 16 | 17 | const T& getElement(std::size_t index) { 18 | SPCPPL_ASSERT(index < n); 19 | return values[index + shift]; 20 | } 21 | 22 | T getResult(std::size_t l, std::size_t r) const { 23 | SPCPPL_ASSERT(l <= r && r <= n); 24 | return internalGetResult(l + shift, r + shift); 25 | } 26 | 27 | template 28 | void update(std::size_t index, const Updater& updater) { 29 | SPCPPL_ASSERT(index < n); 30 | index += shift; 31 | updater(values[index]); 32 | for (std::size_t parent = index / 2; parent > 0; parent /= 2) { 33 | this->recalculate(parent); 34 | } 35 | } 36 | 37 | void set(std::size_t index, const T& value) { 38 | return update(index, [&value](T& element) { 39 | element = value; 40 | }); 41 | } 42 | 43 | template 44 | std::size_t descend(Visitor visit) const { 45 | size_t v = 1; 46 | while (v < shift) { 47 | if (visit(values[v], values[2 * v], values[2 * v + 1])) { 48 | v = 2 * v; 49 | } else { 50 | v = 2 * v + 1; 51 | } 52 | } 53 | return v - shift; 54 | } 55 | 56 | protected: 57 | using Base::n; 58 | using Base::defaultValue; 59 | using Base::shift; 60 | using Base::values; 61 | using Base::merge; 62 | 63 | private: 64 | T internalGetResult(std::size_t l, std::size_t r) const { 65 | if (l == r) { 66 | return defaultValue; 67 | } 68 | if (l & 1) { 69 | return merge(values[l], internalGetResult(l + 1, r)); 70 | } 71 | if (r & 1) { 72 | return merge(internalGetResult(l, r - 1), values[r - 1]); 73 | } 74 | return internalGetResult(l / 2, r / 2); 75 | } 76 | }; 77 | -------------------------------------------------------------------------------- /spcppl/dataStructures/segmentTree/BottomUpSumSegementTree.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include "BottomUpSegmentTree.hpp" 5 | 6 | template 7 | class BottomUpSumSegmentTree: public BottomUpSegmentTree> { 8 | public: 9 | template 10 | explicit BottomUpSumSegmentTree( 11 | const R& range, 12 | const T& zero = T() 13 | ): BottomUpSegmentTree>(range, zero) { 14 | } 15 | 16 | }; 17 | -------------------------------------------------------------------------------- /spcppl/dataStructures/segmentTree/LazyPointSegmentTree.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | template 8 | class LazyPointSegmentTree { 9 | using size_t = std::size_t; 10 | struct Node { 11 | T value; 12 | size_t l; 13 | size_t r; 14 | }; 15 | 16 | public: 17 | explicit LazyPointSegmentTree( 18 | size_t size, 19 | const T& defaultValue = T(), 20 | const Merge& merge = Merge() 21 | ): 22 | size(size), 23 | defaultValue(defaultValue), 24 | merge(merge) { 25 | createNode(); 26 | } 27 | 28 | template 29 | void update(size_t index, Updater&& updater) { 30 | SPCPPL_ASSERT(index <= size); 31 | return internalUpdate(0, 0, size, index, std::forward(updater)); 32 | } 33 | 34 | T getResult(size_t l, size_t r) { 35 | SPCPPL_ASSERT(l <= r && r <= size); 36 | return internalGet(0, 0, size, l, r); 37 | } 38 | 39 | private: 40 | void recalculate(size_t v) { 41 | if (nodes[v].l == 0) { 42 | nodes[v].value = nodes[nodes[v].r].value; 43 | return; 44 | } 45 | if (nodes[v].r == 0) { 46 | nodes[v].value = nodes[nodes[v].l].value; 47 | return; 48 | } 49 | nodes[v].value = merge(nodes[nodes[v].l].value, nodes[nodes[v].r].value); 50 | } 51 | 52 | template 53 | void internalUpdate(size_t v, size_t vl, size_t vr, size_t index, Updater&& updater) { 54 | if (vr - vl == 1) { 55 | SPCPPL_ASSERT(vl == index); 56 | std::forward(updater)(nodes[v].value); 57 | return; 58 | } 59 | size_t vm = vl + (vr - vl) / 2; 60 | if (index < vm) { 61 | if (nodes[v].l == 0) { 62 | size_t l = createNode(); 63 | nodes[v].l = l; 64 | } 65 | internalUpdate(nodes[v].l, vl, vm, index, std::forward(updater)); 66 | } else { 67 | if (nodes[v].r == 0) { 68 | size_t r = createNode(); 69 | nodes[v].r = r; 70 | } 71 | internalUpdate(nodes[v].r, vm, vr, index, std::forward(updater)); 72 | } 73 | recalculate(v); 74 | } 75 | 76 | T internalGet(size_t v, size_t vl, size_t vr, size_t l, size_t r) { 77 | if (r <= vl || l >= vr) { 78 | return defaultValue; 79 | } 80 | if (l <= vl && vr <= r) { 81 | return nodes[v].value; 82 | } 83 | size_t vm = vl + (vr - vl) / 2; 84 | return merge( 85 | nodes[v].l == 0 ? defaultValue : internalGet(nodes[v].l, vl, vm, l, r), 86 | nodes[v].r == 0 ? defaultValue : internalGet(nodes[v].r, vm, vr, l, r) 87 | ); 88 | } 89 | 90 | size_t createNode() { 91 | size_t id = nodes.size(); 92 | nodes.push_back({defaultValue, 0, 0}); 93 | return id; 94 | } 95 | size_t size; 96 | T defaultValue; 97 | Merge merge; 98 | std::vector nodes; 99 | }; 100 | -------------------------------------------------------------------------------- /spcppl/dataStructures/segmentTree/LazyPointSumSegmentTree.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include "LazyPointSegmentTree.hpp" 6 | 7 | template 8 | class LazySumSegmentTree: public LazyPointSegmentTree> { 9 | public: 10 | template 11 | explicit LazySumSegmentTree( 12 | std::size_t n, 13 | const T& zero = T() 14 | ): LazyPointSegmentTree>(n, zero) { 15 | } 16 | 17 | }; 18 | -------------------------------------------------------------------------------- /spcppl/dataStructures/segmentTree/LazySegmentTree.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | template 8 | class LazySegmentTree { 9 | using size_t = std::size_t; 10 | struct Node { 11 | T value; 12 | Update update; 13 | size_t l; 14 | size_t r; 15 | }; 16 | 17 | public: 18 | explicit LazySegmentTree( 19 | size_t size, 20 | const T& defaultValue = T(), 21 | const Merge& merge = Merge(), 22 | const Update& defaultUpdate = Update(), 23 | const ApplyUpdate& applyUpdate = ApplyUpdate(), 24 | const MergeUpdates& mergeUpdates = MergeUpdates() 25 | ): 26 | size(size), 27 | defaultValue(defaultValue), 28 | merge(merge), 29 | defaultUpdate(defaultUpdate), 30 | applyUpdate(applyUpdate), 31 | mergeUpdates(mergeUpdates) { 32 | createNode(); 33 | } 34 | 35 | void update(size_t l, size_t r, const Update& update) { 36 | SPCPPL_ASSERT(l <= r && r <= size); 37 | return internalUpdate(0, 0, size, l, r, update); 38 | } 39 | 40 | T getResult(size_t l, size_t r) { 41 | SPCPPL_ASSERT(l <= r && r <= size); 42 | return internalGet(0, 0, size, l, r); 43 | } 44 | 45 | private: 46 | void recalculate(size_t v) { 47 | nodes[v].value = merge(nodes[nodes[v].l].value, nodes[nodes[v].r].value); 48 | } 49 | 50 | void internalUpdate(size_t v, size_t vl, size_t vr, size_t l, size_t r, const Update& update) { 51 | if (r <= vl || l >= vr) { 52 | return; 53 | } 54 | if (l <= vl && vr <= r) { 55 | nodes[v].value = applyUpdate(nodes[v].value, update, vl, vr); 56 | nodes[v].update = mergeUpdates(nodes[v].update, update); 57 | return; 58 | } 59 | push(v, vl, vr); 60 | size_t vm = vl + (vr - vl) / 2; 61 | internalUpdate(nodes[v].l, vl, vm, l, r, update); 62 | internalUpdate(nodes[v].r, vm, vr, l, r, update); 63 | recalculate(v); 64 | } 65 | 66 | T internalGet(size_t v, size_t vl, size_t vr, size_t l, size_t r) { 67 | if (r <= vl || l >= vr) { 68 | return defaultValue; 69 | } 70 | if (l <= vl && vr <= r) { 71 | return nodes[v].value; 72 | } 73 | push(v, vl, vr); 74 | size_t vm = vl + (vr - vl) / 2; 75 | return merge( 76 | internalGet(nodes[v].l, vl, vm, l, r), 77 | internalGet(nodes[v].r, vm, vr, l, r) 78 | ); 79 | } 80 | 81 | void push(size_t v, size_t vl, size_t vr) { 82 | size_t vm = vl + (vr - vl) / 2; 83 | size_t l = nodes[v].l; 84 | size_t r = nodes[v].r; 85 | if (l == 0) { 86 | l = createNode(); 87 | r = createNode(); 88 | nodes[v].l = l; 89 | nodes[v].r = r; 90 | } 91 | nodes[l].value = applyUpdate(nodes[l].value, nodes[v].update, vl, vm); 92 | nodes[l].update = mergeUpdates(nodes[l].update, nodes[v].update); 93 | nodes[r].value = applyUpdate(nodes[r].value, nodes[v].update, vm, vr); 94 | nodes[r].update = mergeUpdates(nodes[r].update, nodes[v].update); 95 | 96 | nodes[v].update = defaultUpdate; 97 | } 98 | 99 | size_t createNode() { 100 | size_t id = nodes.size(); 101 | nodes.push_back({defaultValue, defaultUpdate, 0, 0}); 102 | return id; 103 | } 104 | size_t size; 105 | T defaultValue; 106 | Merge merge; 107 | Update defaultUpdate; 108 | ApplyUpdate applyUpdate; 109 | MergeUpdates mergeUpdates; 110 | std::vector nodes; 111 | }; 112 | -------------------------------------------------------------------------------- /spcppl/dataStructures/segmentTree/SegementTreeBase.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | template 9 | class SegmentTreeBase { 10 | protected: 11 | explicit SegmentTreeBase(std::size_t n, const T& defaultValue = T(), const Merge& merge = Merge()): 12 | n(n), 13 | defaultValue(defaultValue), 14 | shift(calculateShift(n)), 15 | values(shift << 1, defaultValue), 16 | merge(merge) { 17 | 18 | } 19 | 20 | template ::value>> 21 | explicit SegmentTreeBase(const R& range, const T& defaultValue = T(), const Merge& merge = Merge()) : 22 | SegmentTreeBase( 23 | static_cast(std::distance(std::begin(range), std::end(range))), 24 | defaultValue, 25 | merge 26 | ) { 27 | std::copy(std::begin(range), std::end(range), values.begin() + shift); 28 | for (std::size_t index: downrange(shift, static_cast(1))) { 29 | recalculate(index); 30 | } 31 | } 32 | 33 | static std::size_t calculateShift(std::size_t n) { 34 | std::size_t result = 1; 35 | while (result < n) { 36 | result <<= 1; 37 | } 38 | return result; 39 | } 40 | 41 | void recalculate(std::size_t index) { 42 | values[index] = merge(values[2 * index], values[2 * index + 1]); 43 | } 44 | 45 | std::size_t n; 46 | T defaultValue; 47 | std::size_t shift; 48 | std::vector values; 49 | Merge merge; 50 | }; 51 | -------------------------------------------------------------------------------- /spcppl/dataStructures/segmentTree/TopDownSegementTree.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include "SegementTreeBase.hpp" 6 | 7 | template 8 | class TopDownSegmentTree: protected SegmentTreeBase { 9 | using size_t = std::size_t; 10 | using Base = SegmentTreeBase; 11 | public: 12 | template 13 | explicit TopDownSegmentTree( 14 | const R& range, 15 | const T& defaultValue = T(), 16 | const Merge& merge = Merge(), 17 | const Update& defaultUpdate = Update(), 18 | const ApplyUpdate& applyUpdate = ApplyUpdate(), 19 | const MergeUpdates& mergeUpdates = MergeUpdates() 20 | ): 21 | Base(range, defaultValue, merge), 22 | defaultUpdate(defaultUpdate), 23 | updates(shift << 1, defaultUpdate), 24 | applyUpdate(applyUpdate), 25 | mergeUpdates(mergeUpdates) { 26 | 27 | } 28 | 29 | void update(size_t l, size_t r, const Update& update) { 30 | SPCPPL_ASSERT(l <= r && r <= n); 31 | return internalUpdate(1, 0, shift, l, r, update); 32 | } 33 | 34 | T getResult(size_t l, size_t r) { 35 | SPCPPL_ASSERT(l <= r && r <= n); 36 | return internalGet(1, 0, shift, l, r); 37 | } 38 | 39 | template 40 | std::size_t descend(Visitor visit) { 41 | size_t v = 1; 42 | std::size_t vl = 0; 43 | std::size_t vr = shift; 44 | while (v < shift) { 45 | push(v, vl, vr); 46 | std::size_t vm = vl + (vr - vl) / 2; 47 | if (visit(values[v], values[2 * v], values[2 * v + 1])) { 48 | v = 2 * v; 49 | vr = vm; 50 | } else { 51 | v = 2 * v + 1; 52 | vl = vm; 53 | } 54 | } 55 | return v - shift; 56 | } 57 | 58 | template 59 | std::size_t getFirstPrefix(Predicate predicate) { 60 | if (predicate(defaultValue)) { 61 | return 0; 62 | } 63 | if (!predicate(values[1])) { 64 | return n + 1; 65 | } 66 | T current_left = defaultValue; 67 | return descend([&](const T&, const T& l, const T&) { 68 | auto new_left = merge(current_left, l); 69 | if (predicate(new_left)) { 70 | return true; 71 | } else { 72 | current_left = std::move(new_left); 73 | return false; 74 | } 75 | }) + 1; 76 | } 77 | 78 | protected: 79 | using Base::n; 80 | using Base::defaultValue; 81 | using Base::shift; 82 | using Base::values; 83 | using Base::merge; 84 | private: 85 | 86 | void internalUpdate(size_t v, size_t vl, size_t vr, size_t l, size_t r, const Update& update) { 87 | if (r <= vl || l >= vr) { 88 | return; 89 | } 90 | if (l <= vl && vr <= r) { 91 | values[v] = applyUpdate(values[v], update, vl, vr); 92 | updates[v] = mergeUpdates(updates[v], update); 93 | return; 94 | } 95 | push(v, vl, vr); 96 | size_t vm = vl + (vr - vl) / 2; 97 | internalUpdate(2 * v, vl, vm, l, r, update); 98 | internalUpdate(2 * v + 1, vm, vr, l, r, update); 99 | this->recalculate(v); 100 | } 101 | 102 | T internalGet(size_t v, size_t vl, size_t vr, size_t l, size_t r) { 103 | if (r <= vl || l >= vr) { 104 | return defaultValue; 105 | } 106 | if (l <= vl && vr <= r) { 107 | return values[v]; 108 | } 109 | push(v, vl, vr); 110 | size_t vm = vl + (vr - vl) / 2; 111 | return merge( 112 | internalGet(2 * v, vl, vm, l, r), 113 | internalGet(2 * v + 1, vm, vr, l, r) 114 | ); 115 | } 116 | 117 | void push(size_t v, size_t vl, size_t vr) { 118 | size_t vm = vl + (vr - vl) / 2; 119 | values[2 * v] = applyUpdate(values[2 * v], updates[v], vl, vm); 120 | updates[2 * v] = mergeUpdates(updates[2 * v], updates[v]); 121 | values[2 * v + 1] = applyUpdate(values[2 * v + 1], updates[v], vm, vr); 122 | updates[2 * v + 1] = mergeUpdates(updates[2 * v + 1], updates[v]); 123 | 124 | updates[v] = defaultUpdate; 125 | } 126 | 127 | Update defaultUpdate; 128 | std::vector updates; 129 | ApplyUpdate applyUpdate; 130 | MergeUpdates mergeUpdates; 131 | }; 132 | -------------------------------------------------------------------------------- /spcppl/dataStructures/segmentTree/TopDownSumSegmentTree.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include "TopDownSegementTree.hpp" 5 | 6 | template 7 | struct SumUpdateApplier { 8 | T operator()(const T& value, const T& update, std::size_t l, std::size_t r) const { 9 | return value + update * (r - l); 10 | } 11 | }; 12 | 13 | template 14 | class TopDownSumSegmentTree: 15 | public TopDownSegmentTree, T, SumUpdateApplier, std::plus> { 16 | public: 17 | template 18 | explicit TopDownSumSegmentTree( 19 | const R& range, 20 | const T& zero = T() 21 | ): TopDownSegmentTree, T, SumUpdateApplier, std::plus>(range, zero) { 22 | } 23 | 24 | std::size_t getFirstPrefixAtLeast(const T& expectedSum) { 25 | return this->getFirstPrefix([&](const T& prefixSum) { 26 | return prefixSum >= expectedSum; 27 | }); 28 | } 29 | }; 30 | -------------------------------------------------------------------------------- /spcppl/fft.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | struct Double { 9 | Double(): value(0.0) {} 10 | 11 | Double(double x): value(x) {} 12 | 13 | operator double() { 14 | return value; 15 | } 16 | 17 | Double& operator+=(const Double& x) { 18 | value += x.value; 19 | return *this; 20 | } 21 | 22 | Double& operator-=(const Double& x) { 23 | value -= x.value; 24 | return *this; 25 | } 26 | 27 | Double& operator/=(const Double& x) { 28 | value /= x.value; 29 | return *this; 30 | } 31 | 32 | private: 33 | double value; 34 | }; 35 | 36 | bool isnan(Double d) { 37 | return std::isnan(static_cast(d)); 38 | } 39 | 40 | bool isinf(Double d) { 41 | return std::isinf(static_cast(d)); 42 | } 43 | 44 | using Base = std::complex; 45 | 46 | double impl__cos(std::size_t n) { 47 | static const double PI = acos(-1.0); 48 | static std::vector results = {-1}; 49 | while (n >= results.size()) { 50 | results.push_back(std::cos(2 * PI / results.size())); 51 | } 52 | return results[n]; 53 | } 54 | 55 | double impl__sin(std::size_t n) { 56 | static const double PI = acos(-1.0); 57 | static std::vector results = {-1}; 58 | while (n >= results.size()) { 59 | results.push_back(std::sin(2 * PI / results.size())); 60 | } 61 | return results[n]; 62 | } 63 | 64 | void impl__fft(std::vector& a, bool invert) { 65 | std::size_t n = a.size(); 66 | 67 | for (std::size_t i = 1, j = 0; i < n; ++i) { 68 | std::size_t bit = n >> 1; 69 | for (; j >= bit; bit >>= 1) { 70 | j -= bit; 71 | } 72 | j += bit; 73 | if (i < j) { 74 | swap(a[i], a[j]); 75 | } 76 | } 77 | 78 | for (std::size_t len = 2; len <= n; len <<= 1) { 79 | Base wlen(impl__cos(len), impl__sin(len) * (invert ? -1 : 1)); 80 | for (std::size_t i = 0; i < n; i += len) { 81 | Base w(1); 82 | for (std::size_t j = 0; j < len / 2; ++j) { 83 | Base u = a[i + j], v = a[i + j + len / 2] * w; 84 | a[i + j] = u + v; 85 | a[i + j + len / 2] = u - v; 86 | w = w * wlen; 87 | } 88 | } 89 | } 90 | if (invert) { 91 | for (auto& coef: a) { 92 | coef /= Double(n); 93 | } 94 | } 95 | } 96 | 97 | template ::value> 98 | T impl__convert(double arg) { 99 | if (is_int) { 100 | return static_cast(arg + 0.5); 101 | } 102 | else { 103 | return static_cast(arg); 104 | } 105 | } 106 | 107 | template 108 | std::vector fft_multiply(const std::vector& a, const std::vector& b) { 109 | std::size_t n = 1; 110 | while (n <= a.size() || n <= b.size()) { 111 | n <<= 1; 112 | } 113 | n <<= 1; 114 | std::vector input[2]; 115 | for (std::size_t w = 0; w < 2; ++w) { 116 | input[w].assign(n, Base(0, 0)); 117 | } 118 | for (std::size_t i = 0; i < a.size(); ++i) { 119 | input[0][i] = a[i]; 120 | } 121 | for (std::size_t i = 0; i < b.size(); ++i) { 122 | input[1][i] = b[i]; 123 | } 124 | for (std::size_t w = 0; w < 2; ++w) { 125 | impl__fft(input[w], false); 126 | } 127 | std::vector res(n); 128 | for (std::size_t i = 0; i < n; ++i) { 129 | res[i] = input[0][i] * input[1][i]; 130 | } 131 | impl__fft(res, true); 132 | std::vector answer(n); 133 | for (std::size_t i = 0; i < n; ++i) { 134 | answer[i] = impl__convert(res[i].real()); 135 | } 136 | return answer; 137 | } 138 | -------------------------------------------------------------------------------- /spcppl/flow/AbsoluteMincostFlowStrategy.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | struct AbsoluteMinCostFlowStrategy { 6 | template 7 | FlowSize maximalAdditionFlow(const FlowSize&, const CostSize&, const CostSize& currentCost) { 8 | return currentCost < 0 ? std::numeric_limits::max() : 0; 9 | } 10 | }; 11 | -------------------------------------------------------------------------------- /spcppl/flow/DinicFlow.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | template 10 | class DinicFlow { 11 | struct Edge { 12 | std::size_t from, to; 13 | FlowSize cap; 14 | FlowSize flow; 15 | }; 16 | public: 17 | explicit DinicFlow(std::size_t n): g(n), queue(n), pointer(n), used(n), d(n) { 18 | } 19 | 20 | void addEdge(std::size_t from, std::size_t to, FlowSize capacity) { 21 | return addTwoSidedEdge(from, to, capacity, 0); 22 | } 23 | 24 | void addTwoSidedEdge(std::size_t from, std::size_t to, FlowSize capacity, FlowSize backwardCapacity) { 25 | SPCPPL_ASSERT(from < g.size()); 26 | SPCPPL_ASSERT(to < g.size()); 27 | Edge edge = {from, to, capacity, 0}; 28 | g[from].push_back(edges.size()); 29 | edges.push_back(edge); 30 | 31 | Edge backwardEdge = {to, from, backwardCapacity, 0}; 32 | g[to].push_back(edges.size()); 33 | edges.push_back(backwardEdge); 34 | } 35 | 36 | Edge getEdge(std::size_t id) { 37 | SPCPPL_ASSERT(id < edges.size()); 38 | return edges[id]; 39 | } 40 | 41 | FlowSize findFlow(std::size_t from, std::size_t to, FlowSize infinity = std::numeric_limits::max()) { 42 | SPCPPL_ASSERT(from < g.size()); 43 | SPCPPL_ASSERT(to < g.size()); 44 | SPCPPL_ASSERT(from != to); 45 | FlowSize flow = 0; 46 | while (bfs(from, to)) { 47 | memset(&pointer[0], 0, sizeof(std::size_t) * pointer.size()); 48 | while (FlowSize pushed = dfs(from, to, infinity)) { 49 | flow += pushed; 50 | } 51 | } 52 | return flow; 53 | } 54 | 55 | std::size_t edgesCount() const { 56 | return edges.size(); 57 | } 58 | 59 | private: 60 | 61 | bool bfs(std::size_t from, std::size_t to) { 62 | memset(&used[0], false, sizeof(char) * used.size()); 63 | std::size_t qh = 0, qt = 0; 64 | queue[qt++] = from; 65 | used[from] = true; 66 | while (qh != qt) { 67 | std::size_t v = queue[qh++]; 68 | for (std::size_t id: g[v]) { 69 | Edge& edge = edges[id]; 70 | if (used[edge.to]) { 71 | continue; 72 | } 73 | if (edge.cap == edge.flow) { 74 | continue; 75 | } 76 | used[edge.to] = true; 77 | d[edge.to] = d[v] + 1; 78 | queue[qt++] = edge.to; 79 | } 80 | } 81 | return used[to]; 82 | } 83 | 84 | FlowSize dfs(std::size_t v, std::size_t to, FlowSize mx) { 85 | if (mx == 0) { 86 | return 0; 87 | } 88 | 89 | if (v == to) { 90 | return mx; 91 | } 92 | 93 | for (std::size_t& i = pointer[v]; i < g[v].size(); ++i) { 94 | std::size_t id = g[v][i]; 95 | Edge& e = edges[id]; 96 | if (d[e.to] == d[v] + 1) { 97 | if (FlowSize pushed = dfs(e.to, to, std::min(mx, e.cap - e.flow))) { 98 | e.flow += pushed; 99 | edges[id ^ 1].flow -= pushed; 100 | return pushed; 101 | } 102 | } 103 | } 104 | return 0; 105 | } 106 | 107 | std::vector> g; 108 | std::vector edges; 109 | 110 | /** 111 | * Variables for actual flow calculation. 112 | * TODO: consider moving them so that they are not stored when not needed 113 | */ 114 | std::vector queue; //std::queue is to slow, not removing values is faster 115 | std::vector pointer; 116 | std::vector used; 117 | std::vector d; 118 | }; 119 | -------------------------------------------------------------------------------- /spcppl/flow/FixedCostMaxFlowStrategy.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include "MinCostFlow.hpp" 5 | 6 | template 7 | struct FixedCostMaxFlowStrategy { 8 | explicit FixedCostMaxFlowStrategy(CostSize maxCost): maxCost(maxCost) { 9 | 10 | } 11 | 12 | template 13 | FlowSize maximalAdditionFlow(const FlowSize&, const CostSize& currentCost, const CostSize& additionalCost) { 14 | if (additionalCost <= 0) { 15 | return std::numeric_limits::max(); 16 | } 17 | return (maxCost - currentCost) / additionalCost; 18 | } 19 | 20 | private: 21 | CostSize maxCost; 22 | }; 23 | -------------------------------------------------------------------------------- /spcppl/flow/FixedFlowMIncostStrategy.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | template 4 | struct FixedFlowMinCostStrategy { 5 | explicit FixedFlowMinCostStrategy(FlowSize maxFlow): maxFlow(maxFlow) { 6 | 7 | } 8 | 9 | template 10 | FlowSize maximalAdditionFlow(const FlowSize& currentFlow, const CostSize&, const CostSize&) { 11 | return maxFlow - currentFlow; 12 | } 13 | 14 | private: 15 | FlowSize maxFlow; 16 | }; 17 | -------------------------------------------------------------------------------- /spcppl/flow/MinCostFlow.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | template 11 | struct CostFlow { 12 | FlowSize flow; 13 | CostSize cost; 14 | }; 15 | 16 | template 17 | class MinCostFlow { 18 | struct Edge { 19 | std::size_t from, to; 20 | FlowSize cap; 21 | FlowSize flow; 22 | CostSize cost; 23 | }; 24 | public: 25 | explicit MinCostFlow(std::size_t n): g(n) { 26 | 27 | } 28 | 29 | void addEdge(std::size_t from, std::size_t to, FlowSize capacity, CostSize cost) { 30 | SPCPPL_ASSERT(from < g.size() && to < g.size()); 31 | Edge edge = {from, to, capacity, 0, cost}; 32 | g[from].push_back(edges.size()); 33 | edges.push_back(edge); 34 | 35 | Edge backwardEdge = {to, from, 0, 0, -cost}; 36 | g[to].push_back(edges.size()); 37 | edges.push_back(backwardEdge); 38 | } 39 | 40 | Edge getEdge(std::size_t id) { 41 | SPCPPL_ASSERT(id < edges.size()); 42 | return edges[id]; 43 | } 44 | 45 | std::size_t edgesCount() const { 46 | return edges.size(); 47 | } 48 | 49 | template 50 | CostFlow findFlow(std::size_t s, std::size_t t, Strategy strategy) { 51 | SPCPPL_ASSERT(s < g.size()); 52 | SPCPPL_ASSERT(t < g.size()); 53 | SPCPPL_ASSERT(s != t); 54 | CostSize cost = 0; 55 | FlowSize flow = 0; 56 | std::size_t n = g.size(); 57 | std::vector potential(n); 58 | const std::size_t NO_PARENT = std::numeric_limits::max(); 59 | { 60 | std::vector p(n, NO_PARENT); 61 | std::vector d(n); 62 | d[s] = 0; 63 | p[s] = s; 64 | bool changed = true; 65 | while (changed) { 66 | changed = false; 67 | for (auto i: range(edges.size())) { 68 | Edge& e = edges[i]; 69 | if (e.cap == e.flow || p[e.from] == -1) { 70 | continue; 71 | } 72 | if (p[e.to] == -1 || d[e.to] > d[e.from] + e.cost) { 73 | d[e.to] = d[e.from] + e.cost; 74 | p[e.to] = i; 75 | changed = true; 76 | } 77 | } 78 | } 79 | potential = std::move(d); 80 | } 81 | while (true) { 82 | std::vector d(n); 83 | std::vector p(n, NO_PARENT); 84 | 85 | using QueueType = std::pair; 86 | std::priority_queue, std::greater> q; 87 | 88 | q.push(std::make_pair(0, s)); 89 | 90 | while (!q.empty()) { 91 | std::size_t v = q.top().second; 92 | CostSize oldD = q.top().first; 93 | q.pop(); 94 | if (oldD != d[v]) { 95 | continue; 96 | } 97 | for (std::size_t id: g[v]) { 98 | Edge& e = edges[id]; 99 | if (e.to == s) { 100 | continue; 101 | } 102 | if (e.cap > e.flow) { 103 | SPCPPL_ASSERT(e.cost + potential[e.from] - potential[e.to] >= 0); 104 | CostSize newd = d[v] + e.cost + potential[e.from] - potential[e.to]; 105 | if (p[e.to] == NO_PARENT || d[e.to] > newd) { 106 | d[e.to] = newd; 107 | p[e.to] = id; 108 | q.push(std::make_pair(d[e.to], e.to)); 109 | } 110 | } 111 | } 112 | } 113 | 114 | if (p[t] == NO_PARENT) { 115 | break; 116 | } 117 | 118 | std::size_t cur = t; 119 | FlowSize maxAdd = strategy.maximalAdditionFlow(flow, cost, potential[t] + d[t]); 120 | 121 | if (maxAdd == 0) { 122 | break; 123 | } 124 | 125 | while (cur != s) { 126 | Edge& e = edges[p[cur]]; 127 | cur = e.from; 128 | maxAdd = std::min(maxAdd, e.cap - e.flow); 129 | } 130 | 131 | flow += maxAdd; 132 | cost += (potential[t] + d[t]) * maxAdd; 133 | cur = t; 134 | while (cur != s) { 135 | std::size_t id = p[cur]; 136 | edges[id].flow += maxAdd; 137 | edges[id ^ 1].flow -= maxAdd; 138 | cur = edges[id].from; 139 | } 140 | 141 | for (auto i: range(n)) { 142 | if (p[i] != NO_PARENT) { 143 | potential[i] = potential[i] + d[i]; 144 | } 145 | } 146 | } 147 | 148 | return {flow, cost}; 149 | 150 | } 151 | 152 | private: 153 | std::vector> g; 154 | std::vector edges; 155 | }; 156 | -------------------------------------------------------------------------------- /spcppl/flow/MinCostMaxFlowStrategy.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | struct MinCostMaxFlowStrategy { 6 | template 7 | FlowSize maximalAdditionFlow(const FlowSize&, const CostSize&, const CostSize&) { 8 | return std::numeric_limits::max(); 9 | } 10 | }; 11 | -------------------------------------------------------------------------------- /spcppl/functors/FunctionIdentity.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | struct FunctionIdentity { 4 | template 5 | constexpr T&& operator()(T&& t) const noexcept { 6 | return std::forward(t); 7 | } 8 | }; 9 | -------------------------------------------------------------------------------- /spcppl/functors/Max.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | struct Max { 6 | template 7 | T operator()(const T& l, const T& r) const { 8 | return std::max(l, r); 9 | } 10 | }; 11 | -------------------------------------------------------------------------------- /spcppl/functors/Min.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | struct Min { 5 | template 6 | T operator()(const T& l, const T& r) const { 7 | return std::min(l, r); 8 | } 9 | }; 10 | -------------------------------------------------------------------------------- /spcppl/functors/NegativeInfinity.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | template 7 | struct NegativeInfinity; 8 | 9 | template 10 | struct NegativeInfinity::type> { 11 | T operator()() const { 12 | return std::numeric_limits::min(); 13 | } 14 | }; 15 | 16 | template 17 | struct NegativeInfinity::type> { 18 | T operator()() const { 19 | static_assert(std::numeric_limits::has_infinity, ""); 20 | return -std::numeric_limits::infinity(); 21 | } 22 | }; 23 | -------------------------------------------------------------------------------- /spcppl/functors/PositiveInfinity.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | //FIXME: remove {} when CPP-1825 fixed. 7 | template 8 | struct PositiveInfinity { 9 | T operator()() const; 10 | }; 11 | 12 | template 13 | struct PositiveInfinity::type> { 14 | T operator()() const { 15 | return std::numeric_limits::max(); 16 | } 17 | }; 18 | 19 | template 20 | struct PositiveInfinity::type> { 21 | T operator()() const { 22 | return std::numeric_limits::infinity(); 23 | } 24 | }; 25 | -------------------------------------------------------------------------------- /spcppl/gauss/determinant.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include "reduceToRowEchelonForm.hpp" 5 | 6 | template 7 | T determinant(Matrix matrix) { 8 | reduceToRowEchelonForm(matrix); 9 | 10 | T result = identity(); 11 | for (std::size_t i: range(matrix.rows())) { 12 | result *= matrix[i][i]; 13 | } 14 | return result; 15 | } 16 | -------------------------------------------------------------------------------- /spcppl/gauss/matrixRank.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include "reduceToRowEchelonForm.hpp" 6 | 7 | template 8 | std::size_t matrixRank(Matrix matrix) { 9 | return reduceToRowEchelonForm(matrix); 10 | } 11 | -------------------------------------------------------------------------------- /spcppl/gauss/reduceToRowEchelonForm.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | template 8 | std::size_t reduceToRowEchelonForm(Matrix& matrix) { 9 | static_assert(!std::is_integral::value, "reduceToRowEchelonForm is disabled for integers because you can't divide them"); 10 | std::size_t rank = 0; 11 | 12 | for (std::size_t column: range(matrix.columns())) { 13 | bool found = false; 14 | for (std::size_t row: range(rank, matrix.rows())) { 15 | if (matrix[row][column] != 0) { 16 | using std::swap; 17 | found = true; 18 | swap(matrix[row], matrix[rank]); 19 | break; 20 | } 21 | } 22 | if (!found) { 23 | continue; 24 | } 25 | 26 | for (std::size_t r: range(rank + 1, matrix.rows())) { 27 | T multiplier = matrix[r][column] / matrix[rank][column]; 28 | for (std::size_t c: range(column, matrix.columns())) { 29 | matrix[r][c] -= multiplier * matrix[rank][c]; 30 | } 31 | SPCPPL_ASSERT(matrix[r][column] == 0); 32 | } 33 | ++rank; 34 | } 35 | return rank; 36 | } 37 | -------------------------------------------------------------------------------- /spcppl/geometry/Point2D.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | template 9 | struct Point2D { 10 | T x, y; 11 | 12 | Point2D(): x(0), y(0) { 13 | } 14 | 15 | Point2D(T x, T y): x(x), y(y) { 16 | } 17 | 18 | SquareT squaredDist() const { 19 | return static_cast(x) * x + static_cast(y) * y; 20 | } 21 | 22 | auto dist() const -> decltype(sqrt(this->squaredDist())) { 23 | return sqrt(squaredDist()); 24 | } 25 | 26 | double angle() const { 27 | return atan2(y, x); 28 | } 29 | 30 | Point2D& operator-=(const Point2D& rhs) { 31 | x -= rhs.x; 32 | y -= rhs.y; 33 | return *this; 34 | } 35 | 36 | Point2D& operator+=(const Point2D& rhs) { 37 | x += rhs.x; 38 | y += rhs.y; 39 | return *this; 40 | } 41 | 42 | Point2D& operator*=(T rhs) { 43 | x *= rhs; 44 | y *= rhs; 45 | return *this; 46 | } 47 | 48 | Point2D& operator/=(T rhs) { 49 | x /= rhs; 50 | y /= rhs; 51 | return *this; 52 | } 53 | 54 | T& operator[](std::size_t i) { 55 | if (i == 0) { 56 | return x; 57 | } 58 | if (i == 1) { 59 | return y; 60 | } 61 | SPCPPL_ASSERT(false); 62 | } 63 | 64 | const T& operator[](std::size_t i) const { 65 | if (i == 0) { 66 | return x; 67 | } 68 | if (i == 1) { 69 | return y; 70 | } 71 | SPCPPL_ASSERT(false); 72 | } 73 | 74 | template 75 | Point2D as() { 76 | return {U(x), U(y)}; 77 | } 78 | 79 | Point2D normalized() const { 80 | static_assert(std::is_floating_point::value, "only implemented for floating point types"); 81 | return *this / dist(); 82 | } 83 | 84 | Point2D rotated(double angle) const { 85 | static_assert(std::is_floating_point::value, "only implemented for floating point types"); 86 | double co = cos(angle); 87 | double si = sin(angle); 88 | return Point2D(x * co - y * si, x * si + y * co); 89 | } 90 | 91 | friend std::ostream& operator<< (std::ostream& stream, Point2D point) { 92 | return stream << "(" << point.x << ", " << point.y << ")"; 93 | } 94 | }; 95 | 96 | template 97 | Point2D operator+(const Point2D& lhs, const Point2D& rhs) { 98 | return Point2D(lhs.x + rhs.x, lhs.y + rhs.y); 99 | } 100 | 101 | template 102 | Point2D operator-(const Point2D& lhs, const Point2D& rhs) { 103 | return Point2D(lhs.x - rhs.x, lhs.y - rhs.y); 104 | } 105 | 106 | template 107 | Point2D operator*(const Point2D& lhs, T rhs) { 108 | return Point2D(lhs.x * rhs, lhs.y * rhs); 109 | } 110 | 111 | template 112 | Point2D operator*(T lhs, const Point2D& rhs) { 113 | return Point2D(lhs * rhs.x, lhs * rhs.y); 114 | } 115 | 116 | template 117 | Point2D operator/(const Point2D& lhs, T rhs) { 118 | return Point2D(lhs.x / rhs, lhs.y / rhs); 119 | } 120 | 121 | template 122 | S operator*(const Point2D& lhs, const Point2D& rhs) { 123 | return static_cast(lhs.x) * rhs.y - static_cast(rhs.x) * lhs.y; 124 | } 125 | 126 | template 127 | S operator%(const Point2D& lhs, const Point2D& rhs) { 128 | return static_cast(lhs.x) * rhs.x + static_cast(lhs.y) * rhs.y; 129 | } 130 | 131 | template 132 | bool operator==(const Point2D& lhs, const Point2D& rhs) { 133 | return lhs.x == rhs.x && lhs.y == rhs.y; 134 | } 135 | 136 | template 137 | bool operator!=(const Point2D& lhs, const Point2D& rhs) { 138 | return !(lhs == rhs); 139 | } 140 | 141 | struct LexicograficallyLess { 142 | template 143 | bool operator()(const Point2D& lhs, const Point2D& rhs) const { 144 | return std::tie(lhs.x, lhs.y) < std::tie(rhs.x, rhs.y); 145 | }; 146 | }; 147 | 148 | template 149 | struct LessByAngle { 150 | explicit LessByAngle(const Point2D& center): center(center) { 151 | } 152 | 153 | bool operator() (Point2D lhs, Point2D rhs) { 154 | lhs -= center; 155 | rhs -= center; 156 | if (upper(lhs) != upper(rhs)) { 157 | return upper(rhs); 158 | } 159 | return lhs * rhs > 0; 160 | } 161 | private: 162 | bool upper(const Point2D& point) { 163 | return point.y > 0 || (point.y == 0 && point.x > 0); 164 | } 165 | Point2D center; 166 | }; 167 | 168 | template 169 | double distance_to_segment(const Point2D& point, const Point2D& b, const Point2D& c) { 170 | static_assert(std::is_floating_point::value, "only implemented for floating point types"); 171 | auto ba = b - point; 172 | auto ca = c - point; 173 | if ((ba - ca) % ba >= 0 && (ca - ba) % ca >= 0) { 174 | return fabs(ba * ca) / (ca - ba).dist(); 175 | } 176 | return std::min(ba.dist(), ca.dist()); 177 | } 178 | 179 | template 180 | double distance_to_line(const Point2D& point, const Point2D& b, const Point2D& c) { 181 | static_assert(std::is_floating_point::value, "only implemented for floating point types"); 182 | auto ba = b - point; 183 | auto ca = c - point; 184 | return fabs(ba * ca) / (ca - ba).dist(); 185 | } 186 | 187 | 188 | template 189 | S doubledArea(const Point2D& a, const Point2D& b, const Point2D& c) { 190 | return std::abs((b - a) * (c - a)); 191 | } 192 | -------------------------------------------------------------------------------- /spcppl/geometry/Point3D.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | template 7 | struct Point3D { 8 | T x, y, z; 9 | 10 | Point3D(): x(0), y(0), z(0) { 11 | } 12 | 13 | Point3D(T x, T y, T z): x(x), y(y), z(z) { 14 | } 15 | 16 | SquareT squaredDist() const { 17 | return static_cast(x) * x + static_cast(y) * y + static_cast(z) * z; 18 | } 19 | 20 | auto dist() const -> decltype(sqrt(this->squaredDist())) { 21 | return sqrt(squaredDist()); 22 | } 23 | 24 | Point3D& operator-= (const Point3D& rhs) { 25 | x -= rhs.x; 26 | y -= rhs.y; 27 | z -= rhs.z; 28 | return *this; 29 | } 30 | 31 | Point3D& operator+= (const Point3D& rhs) { 32 | x += rhs.x; 33 | y += rhs.y; 34 | z += rhs.z; 35 | return *this; 36 | } 37 | 38 | Point3D& operator*=(T rhs) { 39 | x *= rhs; 40 | y *= rhs; 41 | z *= rhs; 42 | return *this; 43 | } 44 | 45 | Point3D& operator/=(T rhs) { 46 | x /= rhs; 47 | y /= rhs; 48 | z /= rhs; 49 | return *this; 50 | } 51 | 52 | T& operator[](std::size_t i) { 53 | if (i == 0) { 54 | return x; 55 | } 56 | if (i == 1) { 57 | return y; 58 | } 59 | if (i == 2) { 60 | return z; 61 | } 62 | SPCPPL_ASSERT(false); 63 | } 64 | 65 | const T& operator[](std::size_t i) const { 66 | if (i == 0) { 67 | return x; 68 | } 69 | if (i == 1) { 70 | return y; 71 | } 72 | if (i == 2) { 73 | return z; 74 | } 75 | SPCPPL_ASSERT(false); 76 | } 77 | 78 | template 79 | Point3D as() { 80 | return {U(x), U(y), U(z)}; 81 | } 82 | 83 | Point3D normalized() const { 84 | static_assert(std::is_floating_point::value, "only implemented for floating point types"); 85 | return *this / dist(); 86 | } 87 | }; 88 | 89 | template 90 | Point3D operator+(Point3D lhs, const Point3D& rhs) { 91 | return lhs += rhs; 92 | }; 93 | 94 | template 95 | Point3D operator-(Point3D lhs, const Point3D& rhs) { 96 | return lhs -= rhs; 97 | }; 98 | 99 | template 100 | Point3D operator*(T lhs, Point3D rhs) { 101 | return rhs *= lhs; 102 | }; 103 | 104 | template 105 | Point3D operator*(Point3D lhs, T rhs) { 106 | return lhs *= rhs; 107 | }; 108 | 109 | template 110 | Point3D operator/(const Point3D& lhs, T rhs) { 111 | return Point3D(lhs.x / rhs, lhs.y / rhs, lhs.z / rhs); 112 | } 113 | 114 | template 115 | Point3D operator*(const Point3D& lhs, const Point3D& rhs) { 116 | return Point3D( 117 | lhs.y * rhs.z - lhs.z * rhs.y, 118 | lhs.z * rhs.x - lhs.x * rhs.z, 119 | lhs.x * rhs.y - lhs.y * rhs.x 120 | ); 121 | } 122 | 123 | template 124 | S operator%(const Point3D& lhs, const Point3D& rhs) { 125 | return static_cast(lhs.x) * rhs.x + static_cast(lhs.y) * rhs.y + static_cast(lhs.z) * rhs.z; 126 | } 127 | 128 | template 129 | bool operator==(const Point3D& lhs, const Point3D& rhs) { 130 | return lhs.x == rhs.x && lhs.y == rhs.y && lhs.z == rhs.z; 131 | } 132 | 133 | template 134 | bool operator!=(const Point3D& lhs, const Point3D& rhs) { 135 | return !(lhs == rhs); 136 | } 137 | -------------------------------------------------------------------------------- /spcppl/geometry/convexHull.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | template 10 | auto convexHull(Collection points, Proj proj = {}) { 11 | using T = typename Collection::value_type; 12 | LexicograficallyLess less; 13 | 14 | sort(points, [&](const auto& lhs, const auto& rhs) { 15 | return less(proj(lhs), proj(rhs)); 16 | }); 17 | 18 | std::vector top; 19 | for (const auto& elem: points) { 20 | while (top.size() >= 2 && 21 | ((proj(top[top.size() - 1]) - proj(top[top.size() - 2])) * (proj(elem) - proj(top.back())) >= 0)) { 22 | top.pop_back(); 23 | } 24 | top.push_back(elem); 25 | } 26 | std::vector bottom; 27 | 28 | 29 | for (const auto& elem: points) { 30 | while (bottom.size() >= 2 && 31 | ((proj(bottom[bottom.size() - 1]) - proj(bottom[bottom.size() - 2])) * (proj(elem) - proj(bottom.back())) <= 0)) { 32 | bottom.pop_back(); 33 | } 34 | bottom.push_back(elem); 35 | } 36 | bottom.insert(bottom.end(), std::next(top.rbegin()), prev(top.rend())); 37 | return bottom; 38 | } 39 | -------------------------------------------------------------------------------- /spcppl/graphs/SimpleGraph.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "VectorVectorBaseGraph.hpp" 4 | 5 | class SimpleGraph: public VectorVectorBaseGraph { 6 | public: 7 | explicit SimpleGraph(std::size_t n): VectorVectorBaseGraph(n) {} 8 | 9 | Vertex endOfEdge(Vertex, Edge edge) const { 10 | return edge; 11 | } 12 | 13 | void addEdge(Vertex from, Vertex to) { 14 | g[from].push_back(to); 15 | } 16 | }; 17 | -------------------------------------------------------------------------------- /spcppl/graphs/VectorVectorBaseGraph.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | template 7 | class VectorVectorBaseGraph { 8 | public: 9 | using Edge = T; 10 | using Vertex = std::size_t; 11 | 12 | explicit VectorVectorBaseGraph(std::size_t n): g(n) { 13 | } 14 | 15 | template 16 | using Collection = std::vector; 17 | 18 | template 19 | Collection getCollection(const U& defaultValue) const { 20 | return Collection(g.size(), defaultValue); 21 | } 22 | 23 | IntegerRange vertices() const { 24 | return range(g.size()); 25 | } 26 | 27 | const std::vector& outgoingEdges(Vertex vertex) const { 28 | return g[vertex]; 29 | } 30 | protected: 31 | std::vector> g; 32 | }; 33 | -------------------------------------------------------------------------------- /spcppl/graphs/WeightedGraph.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "VectorVectorBaseGraph.hpp" 4 | 5 | template 6 | class WeightedGraph: public VectorVectorBaseGraph> { 7 | using Base = VectorVectorBaseGraph>; 8 | public: 9 | using Length = T; 10 | using Vertex = typename Base::Vertex; 11 | using Edge = typename Base::Edge; 12 | using Base::g; 13 | explicit WeightedGraph(std::size_t n): Base(n) {} 14 | 15 | Vertex endOfEdge(Vertex, Edge edge) const { 16 | return edge.first; 17 | } 18 | 19 | void addEdge(Vertex from, Vertex to, const Length& l) { 20 | g[from].emplace_back(to, l); 21 | } 22 | 23 | Length edgeLength(Vertex, const Edge& e) const { 24 | return e.second; 25 | } 26 | }; 27 | -------------------------------------------------------------------------------- /spcppl/graphs/algorithms/bfs.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | template 6 | std::vector bfsDistances(const Graph& graph, const typename Graph::Vertex& from) { 7 | auto result = graph.getCollection(-1); 8 | std::queue q; 9 | q.push(from); 10 | result[from] = 0; 11 | while (!q.empty()) { 12 | const auto& v = q.front(); 13 | for (const auto& e: graph.outgoingEdges(v)) { 14 | const auto& to = graph.endOfEdge(v, e); 15 | if (result[to] == -1) { 16 | result[to] = result[v] + 1; 17 | q.push(to); 18 | } 19 | } 20 | q.pop(); 21 | } 22 | return result; 23 | } 24 | -------------------------------------------------------------------------------- /spcppl/graphs/algorithms/dijkstra.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | template < 10 | typename Graph, 11 | typename Length = typename Graph::Length, 12 | typename Vertex = typename Graph::Vertex 13 | > 14 | auto dijkstraDistances( 15 | const Graph& graph, 16 | const Vertex& start, 17 | const Length& infinity = PositiveInfinity()() 18 | ) -> decltype(graph.getCollection(infinity)) { 19 | auto used = graph.getCollection(char()); 20 | auto distance = graph.getCollection(infinity); 21 | using QueueElement = std::pair; 22 | std::priority_queue, std::greater> queue; 23 | queue.emplace(0, start); 24 | distance[start] = 0; 25 | while (!queue.empty()) { 26 | Vertex v = queue.top().second; 27 | SPCPPL_ASSERT(distance[v] == queue.top().first); 28 | queue.pop(); 29 | if (used[v]) { 30 | continue; 31 | } 32 | used[v] = true; 33 | for (const auto& e: graph.outgoingEdges(v)) { 34 | const auto& to = graph.endOfEdge(v, e); 35 | Length newLength = distance[v] + graph.edgeLength(v, e); 36 | if (distance[to] > newLength) { 37 | distance[to] = newLength; 38 | queue.emplace(distance[to], to); 39 | } 40 | } 41 | } 42 | return distance; 43 | }; 44 | -------------------------------------------------------------------------------- /spcppl/graphs/algorithms/dynamicConnectivityOffline.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | // todo: support different types of queries 13 | struct DynamicConnectivityQuery { 14 | std::size_t a; 15 | std::size_t b; 16 | std::size_t time; 17 | }; 18 | 19 | struct TimedEdge { 20 | std::size_t a; 21 | std::size_t b; 22 | std::size_t beginTime; 23 | std::size_t endTime; 24 | }; 25 | 26 | struct DynamicConnectivityTest { 27 | std::vector queries; 28 | std::vector edges; 29 | std::size_t timeRange; 30 | }; 31 | 32 | class DynamicConnectivityTestBuilder { 33 | public: 34 | void addEdge(std::size_t a, std::size_t b) { 35 | if (a > b) { 36 | std::swap(a, b); 37 | } 38 | edgeStart[{a, b}] = ++time; 39 | } 40 | 41 | void removeEdge(std::size_t a, std::size_t b) { 42 | if (a > b) { 43 | std::swap(a, b); 44 | } 45 | auto it = edgeStart.find({a, b}); 46 | SPCPPL_ASSERT(it != edgeStart.end()); 47 | edges.push_back({a, b, it->second, ++time}); 48 | edgeStart.erase(it); 49 | } 50 | 51 | void addQuery(std::size_t a, std::size_t b) { 52 | queries.push_back({a, b, time}); 53 | } 54 | 55 | DynamicConnectivityTest build() && { 56 | ++time; 57 | for (auto& p : edgeStart) { 58 | edges.push_back({p.first.first, p.first.second, p.second, time}); 59 | } 60 | edgeStart.clear(); 61 | return DynamicConnectivityTest{ 62 | std::move(queries), 63 | std::move(edges), 64 | time 65 | }; 66 | } 67 | 68 | private: 69 | using Edge = std::pair; 70 | std::size_t time = 0; 71 | std::vector queries; 72 | std::vector edges; 73 | std::map edgeStart; 74 | }; 75 | 76 | class DynamicConnectivitySolver { 77 | public: 78 | explicit DynamicConnectivitySolver(std::vector&& queries): 79 | queries(std::move(queries)) { 80 | answers.reserve(queries.size()); 81 | } 82 | 83 | void solve( 84 | std::size_t l, 85 | std::size_t r, 86 | const std::vector& edges, 87 | std::size_t n 88 | ) { 89 | if (answers.size() == queries.size() || queries[answers.size()].time >= r) { 90 | return; 91 | } 92 | if (edges.empty()) { 93 | while (answers.size() != queries.size() && queries[answers.size()].time < r) { 94 | const auto& query = queries[answers.size()]; 95 | answers.push_back(query.a == query.b); 96 | } 97 | return; 98 | } 99 | 100 | DSU dsu(n); 101 | std::vector filteredEdges; 102 | for (auto& edge: edges) { 103 | if (edge.beginTime <= l && r <= edge.endTime) { 104 | dsu.unite(edge.a, edge.b); 105 | } 106 | else if (edge.endTime <= l || edge.beginTime >= r) { 107 | // no intersection 108 | } 109 | else { 110 | filteredEdges.push_back(edge); 111 | } 112 | } 113 | 114 | std::vector hasEdges(n); 115 | for (auto& edge: filteredEdges) { 116 | SPCPPL_ASSERT(edge.a < n); 117 | SPCPPL_ASSERT(edge.b < n); 118 | hasEdges[dsu.getSet(edge.a)] = true; 119 | hasEdges[dsu.getSet(edge.b)] = true; 120 | } 121 | 122 | std::vector color(n); 123 | std::size_t usedRealColors = 0; 124 | std::size_t lastUsedColor = dsu.components(); 125 | for (auto i: range(n)) { 126 | if (dsu.getSet(i) == i) { 127 | if (hasEdges[dsu.getSet(i)]) { 128 | color[i] = usedRealColors++; 129 | } 130 | else { 131 | color[i] = --lastUsedColor; 132 | } 133 | } 134 | } 135 | 136 | for (auto i: range(n)) { 137 | color[i] = color[dsu.getSet(i)]; 138 | } 139 | 140 | SPCPPL_ASSERT(usedRealColors == lastUsedColor); 141 | 142 | for (std::size_t i = answers.size(); i < queries.size() && queries[i].time < r; ++i) { 143 | if (queries[i].a < n) { 144 | queries[i].a = color[queries[i].a]; 145 | } 146 | if (queries[i].b < n) { 147 | queries[i].b = color[queries[i].b]; 148 | } 149 | } 150 | 151 | for (auto& edge: filteredEdges) { 152 | edge.a = color[edge.a]; 153 | edge.b = color[edge.b]; 154 | } 155 | 156 | auto m = (l + r) / 2; 157 | solve(l, m, filteredEdges, usedRealColors); 158 | solve(m, r, filteredEdges, usedRealColors); 159 | } 160 | 161 | std::vector queries; 162 | std::vector answers; 163 | }; 164 | 165 | std::vector dynamicConnectivity(DynamicConnectivityTest test, std::size_t n) { 166 | auto x = DynamicConnectivitySolver(std::move(test.queries)); 167 | x.solve(0, test.timeRange, test.edges, n); 168 | return std::move(x.answers); 169 | } 170 | -------------------------------------------------------------------------------- /spcppl/graphs/algorithms/findIndependentSetInBipartiteGraph.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | namespace impl { 10 | 11 | constexpr std::size_t noPair = std::numeric_limits::max(); 12 | 13 | class MatchingFinder { 14 | public: 15 | MatchingFinder( 16 | const std::vector>& graph, 17 | std::vector& mt 18 | ): graph(graph), mt(mt), used(graph.size()) { 19 | } 20 | 21 | bool tryPushAugumentingPath(std::size_t v) { 22 | if (used[v]) { 23 | return false; 24 | } 25 | used[v] = true; 26 | for (std::size_t i: range(graph[v].size())) { 27 | auto to = graph[v][i]; 28 | if (mt[to] == noPair || tryPushAugumentingPath(mt[to])) { 29 | mt[to] = v; 30 | return true; 31 | } 32 | } 33 | return false; 34 | } 35 | 36 | void clearUsed() { 37 | std::fill(used.begin(), used.end(), false); 38 | } 39 | 40 | private: 41 | const std::vector>& graph; 42 | std::vector& mt; 43 | std::vector used; 44 | }; 45 | 46 | class IndependentSetFinder { 47 | public: 48 | IndependentSetFinder( 49 | const std::vector>& graph, 50 | std::vector& mt 51 | ): 52 | graph(graph), 53 | mt(mt), 54 | inAnswerLeft(graph.size(), true), 55 | inAnswerRight(mt.size(), true), 56 | inMatchLeft(graph.size()) { 57 | } 58 | 59 | std::pair, std::vector> find() { 60 | for (auto v: mt) { 61 | if (v != noPair) { 62 | inMatchLeft[v] = true; 63 | inAnswerLeft[v] = false; 64 | } 65 | } 66 | for (auto i: range(graph.size())) { 67 | if (!inMatchLeft[i]) { 68 | dfs(i); 69 | } 70 | } 71 | return {inAnswerLeft, inAnswerRight}; 72 | } 73 | 74 | private: 75 | void dfs(std::size_t v) { 76 | for (auto to: graph[v]) { 77 | if (inAnswerRight[to]) { 78 | inAnswerRight[to] = false; 79 | SPCPPL_ASSERT(mt[to] != noPair); 80 | SPCPPL_ASSERT(!inAnswerLeft[mt[to]]); 81 | inAnswerLeft[mt[to]] = true; 82 | dfs(mt[to]); 83 | } 84 | } 85 | } 86 | 87 | const std::vector>& graph; 88 | std::vector& mt; 89 | std::vector inAnswerLeft; 90 | std::vector inAnswerRight; 91 | std::vector inMatchLeft; 92 | }; 93 | 94 | } // namespace impl 95 | 96 | std::pair, std::vector> findIndependentSetInBipartiteGraph( 97 | const std::vector>& graph, 98 | std::size_t rightSize 99 | ) { 100 | std::size_t leftSize = graph.size(); 101 | 102 | std::vector mt(rightSize, impl::noPair); 103 | 104 | impl::MatchingFinder dfser(graph, mt); 105 | for (auto v: range(leftSize)) { 106 | dfser.clearUsed(); 107 | dfser.tryPushAugumentingPath(v); 108 | } 109 | 110 | impl::IndependentSetFinder finder(graph, mt); 111 | auto maps = finder.find(); 112 | 113 | auto indices = [](const std::vector& map) { 114 | std::vector result; 115 | result.reserve(map.size()); 116 | for (auto index: range(map.size())) { 117 | if (map[index]) { 118 | result.push_back(index); 119 | } 120 | } 121 | return result; 122 | }; 123 | return { 124 | indices(maps.first), 125 | indices(maps.second) 126 | }; 127 | } 128 | -------------------------------------------------------------------------------- /spcppl/identity.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | template 6 | struct IdentityHelper; 7 | 8 | template 9 | struct IdentityHelper::type> { 10 | static T identity() { 11 | return 1; 12 | } 13 | }; 14 | 15 | template 16 | T identity() { 17 | return IdentityHelper::identity(); 18 | } 19 | -------------------------------------------------------------------------------- /spcppl/make_constant.hpp: -------------------------------------------------------------------------------- 1 | #define MAKE_CONSTANT(name, type) \ 2 | struct name { \ 3 | static type value; \ 4 | }; \ 5 | type name::value; 6 | -------------------------------------------------------------------------------- /spcppl/make_vector.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | template 7 | struct MakeVector { 8 | template < 9 | typename... Args, 10 | typename R = std::vector::make_vector(std::declval()...))> 11 | > 12 | static R make_vector(std::size_t first, Args... sizes) { 13 | auto inner = MakeVector::make_vector(sizes...); 14 | return R(first, inner); 15 | } 16 | }; 17 | 18 | template 19 | struct MakeVector { 20 | static std::vector make_vector(std::size_t size, const T& value) { 21 | return std::vector(size, value); 22 | } 23 | }; 24 | 25 | template 26 | auto make_vector(Args... args) -> decltype(MakeVector::make_vector(args...)) { 27 | return MakeVector::make_vector(args...); 28 | } 29 | -------------------------------------------------------------------------------- /spcppl/matrixMultiplication.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | namespace impl { 6 | 7 | template 8 | void matrixMultiplication(const T& lhs, const U& rhs, V& res) { 9 | const auto& a = lhs; 10 | auto b = rhs.transposed(); 11 | for (std::size_t i = 0; i < lhs.rows(); ++i) { 12 | for (std::size_t j = 0; j < rhs.columns(); ++j) { 13 | for (std::size_t k = 0; k < rhs.rows(); ++k) { 14 | res[i][j] += a[i][k] * b[j][k]; 15 | } 16 | } 17 | } 18 | } 19 | 20 | } // namespace impl 21 | -------------------------------------------------------------------------------- /spcppl/numbers/Polynomial.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | -------------------------------------------------------------------------------- /spcppl/numbers/Rational.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include "gcd.hpp" 7 | 8 | template 9 | class Rational { 10 | public: 11 | Rational(): numerator(0), denominator(1) { 12 | } 13 | 14 | Rational(T numerator): numerator(numerator), denominator(1) { 15 | } 16 | 17 | Rational(T numerator, T denominator): numerator(numerator), denominator(denominator) { 18 | SPCPPL_ASSERT(denominator != 0); 19 | normalize(); 20 | } 21 | 22 | Rational& operator+=(const Rational& rhs) { 23 | return *this = *this + rhs; 24 | } 25 | 26 | Rational& operator-=(const Rational& rhs) { 27 | return *this = *this - rhs; 28 | } 29 | 30 | Rational& operator*=(const Rational& rhs) { 31 | numerator *= rhs.numerator; 32 | denominator *= rhs.denominator; 33 | normalize(); 34 | return *this; 35 | } 36 | 37 | Rational operator-() const { 38 | return Rational(-numerator, denominator); 39 | } 40 | 41 | Rational& operator/=(const Rational& rhs) { 42 | SPCPPL_ASSERT(rhs.numerator != 0); 43 | numerator *= rhs.denominator; 44 | denominator *= rhs.numerator; 45 | normalize(); 46 | return *this; 47 | } 48 | 49 | bool operator==(const Rational& rhs) const { 50 | return numerator == rhs.numerator && denominator == rhs.denominator; 51 | } 52 | 53 | const T& getNumerator() const { 54 | return numerator; 55 | } 56 | 57 | const T& getDenominator() const { 58 | return denominator; 59 | } 60 | 61 | private: 62 | void normalize() { 63 | T g = gcd(numerator, denominator); 64 | numerator /= g; 65 | denominator /= g; 66 | 67 | if (denominator < 0) { 68 | numerator = -numerator; 69 | denominator = -denominator; 70 | } 71 | } 72 | 73 | T numerator, denominator; 74 | 75 | template 76 | friend Rational operator+(const Rational& lhs, const Rational& rhs); 77 | }; 78 | 79 | 80 | template 81 | Rational operator+(const Rational& lhs, const Rational& rhs) { 82 | T g = gcd(lhs.denominator, rhs.denominator); 83 | return Rational( 84 | lhs.numerator * (rhs.denominator / g) + rhs.numerator * (lhs.denominator / g), 85 | lhs.denominator / g * rhs.denominator 86 | ); 87 | } 88 | 89 | template 90 | Rational operator-(const Rational& lhs, const Rational& rhs) { 91 | return lhs + (-rhs); 92 | } 93 | 94 | template 95 | Rational operator*(const Rational& lhs, const Rational& rhs) { 96 | Rational copy = lhs; 97 | return copy *= rhs; 98 | } 99 | 100 | template 101 | Rational operator/(const Rational& lhs, const Rational& rhs) { 102 | Rational copy = lhs; 103 | return copy /= rhs; 104 | } 105 | 106 | template 107 | std::ostream& operator<<(std::ostream& stream, const Rational& rational) { 108 | return stream << rational.getNumerator() << '/' << rational.getDenominator(); 109 | } 110 | 111 | template 112 | struct IdentityHelper> { 113 | static Rational identity() { 114 | return Rational(1); 115 | } 116 | }; 117 | 118 | template 119 | bool operator==(const Rational& lhs, const Rational& rhs) { 120 | return lhs.getNumerator() * rhs.getDenominator() == lhs.getDenominator() * rhs.getNumerator(); 121 | } 122 | 123 | template 124 | bool operator!=(const Rational& lhs, const Rational& rhs) { 125 | return !(lhs == rhs); 126 | } 127 | 128 | template 129 | bool operator<(const Rational& lhs, const Rational& rhs) { 130 | return lhs.getNumerator() * rhs.getDenominator() < lhs.getDenominator() * rhs.getNumerator(); 131 | } 132 | 133 | template 134 | bool operator>(const Rational& lhs, const Rational& rhs) { 135 | return rhs < lhs; 136 | } 137 | 138 | template 139 | bool operator<=(const Rational& lhs, const Rational& rhs) { 140 | return !(lhs > rhs); 141 | } 142 | 143 | template 144 | bool operator>=(const Rational& lhs, const Rational& rhs) { 145 | return !(lhs < rhs); 146 | } 147 | 148 | -------------------------------------------------------------------------------- /spcppl/numbers/Zn.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include "extendedGcd.hpp" 11 | 12 | template 13 | class Zn { 14 | public: 15 | Zn(): value(0) { 16 | } 17 | 18 | /** 19 | * Instead of ctor, to allow not to normalize in ctor 20 | */ 21 | template 22 | static Zn valueOf(U value) { 23 | int x = static_cast(value % mod()); 24 | if (x < 0) { 25 | x += mod(); 26 | } 27 | return Zn(x); 28 | } 29 | 30 | static Zn rawValueOf(int value) { 31 | SPCPPL_ASSERT(value >= 0 && value < mod()); 32 | return Zn(value); 33 | } 34 | 35 | template 36 | Zn& operator=(U rhs) { 37 | return *this = Zn::valueOf(rhs); 38 | } 39 | 40 | 41 | Zn& operator+=(const Zn& rhs) { 42 | value += rhs.value; 43 | if (value >= mod()) { 44 | value -= mod(); 45 | } 46 | return *this; 47 | } 48 | 49 | template 50 | Zn& operator+=(U rhs) { 51 | return *this += Zn::valueOf(rhs); 52 | } 53 | 54 | Zn& operator-=(const Zn& rhs) { 55 | value -= rhs.value; 56 | if (value < 0) { 57 | value += mod(); 58 | } 59 | return *this; 60 | } 61 | 62 | template 63 | Zn& operator-=(U rhs) { 64 | return *this -= Zn::valueOf(rhs); 65 | } 66 | 67 | Zn& operator*=(const Zn& rhs) { 68 | long long result = static_cast(value) * static_cast(rhs.value); 69 | value = static_cast(result % mod()); 70 | return *this; 71 | } 72 | 73 | template 74 | Zn& operator*=(U rhs) { 75 | return *this *= Zn::valueOf(rhs); 76 | } 77 | 78 | Zn operator-() const { 79 | if (value == 0) { 80 | return *this; 81 | } 82 | else { 83 | return Zn(mod() - value); 84 | } 85 | } 86 | 87 | Zn& operator/=(const Zn& rhs) { 88 | return *this *= rhs.inversed(); 89 | } 90 | 91 | template 92 | Zn& operator/=(U rhs) { 93 | return *this /= Zn::valueOf(rhs); 94 | } 95 | 96 | Zn inversed() const { 97 | SPCPPL_ASSERT(value != 0); 98 | 99 | int x, y; 100 | int gcd = extendedGcd(value, mod(), x, y); 101 | (void) gcd; 102 | SPCPPL_ASSERT(gcd == 1); 103 | 104 | if (x < 0) { 105 | x += mod(); 106 | } 107 | return Zn(x); 108 | } 109 | 110 | template 111 | friend std::ostream& operator<<(std::ostream&, const Zn& zn); 112 | 113 | template 114 | friend std::istream& operator>>(std::istream&, Zn& zn); 115 | 116 | template 117 | friend bool operator==(const Zn& lhs, const Zn& rhs); 118 | 119 | int intValue() const { 120 | return value; 121 | } 122 | 123 | private: 124 | /** 125 | * No normalization performed 126 | */ 127 | explicit Zn(int value): value(value) { 128 | } 129 | 130 | int value; 131 | 132 | constexpr static int mod() { 133 | return T::value; 134 | } 135 | 136 | template 137 | static constexpr bool correct_or_runtime(int) { 138 | return N > 0 && N <= (1 << 30); 139 | } 140 | static constexpr bool correct_or_runtime(...) { 141 | return true; 142 | } 143 | static_assert( 144 | std::is_same::type, int>::value, 145 | "T::value must be int" 146 | ); 147 | static_assert(correct_or_runtime(0), "Mod has to be positive integer up to 1 << 30"); 148 | }; 149 | 150 | template 151 | bool operator==(const Zn& lhs, const Zn& rhs) { 152 | return lhs.value == rhs.value; 153 | } 154 | 155 | template 156 | bool operator==(const Zn& lhs, U rhs) { 157 | return lhs == Zn::valueOf(rhs); 158 | } 159 | 160 | template 161 | bool operator==(U lhs, const Zn& rhs) { 162 | return rhs == lhs; 163 | } 164 | 165 | template 166 | bool operator!=(const Zn& lhs, const Zn& rhs) { 167 | return !(lhs == rhs); 168 | } 169 | 170 | template 171 | bool operator!=(const Zn& lhs, U rhs) { 172 | return !(lhs == rhs); 173 | } 174 | 175 | template 176 | bool operator!=(U lhs, const Zn& rhs) { 177 | return !(lhs == rhs); 178 | } 179 | 180 | template 181 | Zn operator+(const Zn& lhs, const Zn& rhs) { 182 | Zn copy = lhs; 183 | return copy += rhs; 184 | } 185 | 186 | template 187 | Zn operator+(const Zn& lhs, U rhs) { 188 | Zn copy = lhs; 189 | return copy += rhs; 190 | } 191 | 192 | template 193 | Zn operator+(U lhs, const Zn& rhs) { 194 | return rhs + lhs; 195 | } 196 | 197 | template 198 | Zn operator-(const Zn& lhs, const Zn& rhs) { 199 | Zn copy = lhs; 200 | return copy -= rhs; 201 | } 202 | 203 | template 204 | Zn operator-(const Zn& lhs, U rhs) { 205 | Zn copy = lhs; 206 | return copy -= rhs; 207 | } 208 | 209 | template 210 | Zn operator-(U lhs, const Zn& rhs) { 211 | return Zn::valueOf(lhs) - rhs; 212 | } 213 | 214 | template 215 | Zn operator*(const Zn& lhs, const Zn& rhs) { 216 | Zn copy = lhs; 217 | return copy *= rhs; 218 | } 219 | 220 | template 221 | Zn operator*(const Zn& lhs, U rhs) { 222 | Zn copy = lhs; 223 | return copy *= rhs; 224 | } 225 | 226 | template 227 | Zn operator*(U lhs, const Zn& rhs) { 228 | return rhs * lhs; 229 | } 230 | 231 | template 232 | Zn operator/(const Zn& lhs, const Zn& rhs) { 233 | Zn copy = lhs; 234 | return copy /= rhs; 235 | } 236 | 237 | template 238 | Zn operator/(const Zn& lhs, U rhs) { 239 | Zn copy = lhs; 240 | return copy /= rhs; 241 | } 242 | 243 | template 244 | Zn operator/(U lhs, const Zn& rhs) { 245 | return Zn::valueOf(lhs) / rhs; 246 | } 247 | 248 | template 249 | std::ostream& operator<<(std::ostream& stream, const Zn& zn) { 250 | return stream << zn.value; 251 | } 252 | 253 | template 254 | std::istream& operator>>(std::istream& stream, Zn& zn) { 255 | int64_t value; 256 | stream >> value; 257 | zn.value = static_cast(value % T::value); 258 | return stream; 259 | } 260 | 261 | template 262 | struct IdentityHelper> { 263 | static Zn identity() { 264 | return Zn::valueOf(1); 265 | } 266 | }; 267 | 268 | template 269 | using ZnConst = Zn>; 270 | 271 | using Zn7 = ZnConst<1000000007>; 272 | -------------------------------------------------------------------------------- /spcppl/numbers/bits.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | template 7 | std::size_t leastSignificantBit(T number) { 8 | SPCPPL_ASSERT(number != 0); 9 | for (std::size_t i = 0; ; ++i) { 10 | if ((number >> i) & 1) { 11 | return i; 12 | } 13 | } 14 | } 15 | 16 | template 17 | bool isPowerOf2(T number) { 18 | return number != 0 && (number & (number - 1)) == 0; 19 | } 20 | -------------------------------------------------------------------------------- /spcppl/numbers/division.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | template 6 | T divideCeil(T a, T b) { 7 | SPCPPL_ASSERT(b != 0); 8 | if (b < 0) { 9 | a = -a; 10 | b = -b; 11 | } 12 | return a / b + (a % b > 0); 13 | } 14 | 15 | template 16 | T divideFloor(T a, T b) { 17 | SPCPPL_ASSERT(b != 0); 18 | if (b < 0) { 19 | a = -a; 20 | b = -b; 21 | } 22 | return a / b - (a % b < 0); 23 | } 24 | 25 | template 26 | T divideTowardsZero(T a, T b) { 27 | SPCPPL_ASSERT(b != 0); 28 | return a / b; 29 | } 30 | 31 | template 32 | T divideAwayFromZero(T a, T b) { 33 | SPCPPL_ASSERT(b != 0); 34 | bool changeSign = false; 35 | if (a < 0) { 36 | changeSign = !changeSign; 37 | a = -a; 38 | } 39 | if (b < 0) { 40 | changeSign = !changeSign; 41 | b = -b; 42 | } 43 | T res = (a + b - 1) / b; 44 | if (changeSign) { 45 | res *= -1; 46 | } 47 | return res; 48 | } 49 | 50 | -------------------------------------------------------------------------------- /spcppl/numbers/divisors.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | template 7 | std::vector unsortedDivisors(const T& n) { 8 | std::vector result; 9 | for (int i = 1; static_cast(i) * i <= n; ++i) { 10 | if (n % i == 0) { 11 | result.push_back(i); 12 | if (i * i != n) { 13 | result.push_back(n / i); 14 | } 15 | } 16 | } 17 | return result; 18 | } 19 | 20 | template 21 | std::vector sortedDivisors(const T& n) { 22 | return sorted(unsortedDivisors(n)); 23 | } 24 | -------------------------------------------------------------------------------- /spcppl/numbers/extendedGcd.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | /** 4 | * ax + by = result 5 | */ 6 | template 7 | T extendedGcd(T a, T b, T& x, T& y) { 8 | if (a == 0) { 9 | x = 0; 10 | y = 1; 11 | return b; 12 | } 13 | T d = extendedGcd(b % a, a, y, x); 14 | x -= (b / a) * y; 15 | return d; 16 | } -------------------------------------------------------------------------------- /spcppl/numbers/gcd.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | template 4 | T gcd(T a, T b) { 5 | while (b) { 6 | T tmp = a % b; 7 | a = b; 8 | b = tmp; 9 | } 10 | return a; 11 | } -------------------------------------------------------------------------------- /spcppl/numbers/lcm.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "gcd.hpp" 4 | 5 | template 6 | T lcm(const T& a, const T& b) { 7 | return a * b / gcd(a, b); 8 | } -------------------------------------------------------------------------------- /spcppl/numbers/linearSieve.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | std::vector linearSieve(int maxN) { 7 | SPCPPL_ASSERT(maxN > 0); 8 | std::vector leastPrimes(maxN + 1); 9 | std::vector primes; 10 | 11 | for (int i = 2; i <= maxN; ++i) { 12 | if (leastPrimes[i] == 0) { 13 | leastPrimes[i] = i; 14 | primes.push_back(i); 15 | } 16 | for (int prime: primes) { 17 | if (prime > leastPrimes[i] or i * prime > maxN) { 18 | break; 19 | } 20 | leastPrimes[i * prime] = prime; 21 | } 22 | } 23 | return leastPrimes; 24 | } 25 | -------------------------------------------------------------------------------- /spcppl/numbers/numbers.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | template 10 | T factorial(std::size_t maxN) { 11 | T result = identity(); 12 | for (std::size_t i = 2; i <= maxN; ++i) { 13 | result *= static_cast(i); 14 | } 15 | return result; 16 | } 17 | 18 | template 19 | std::vector factorials(std::size_t maxN) { 20 | std::vector res(maxN + 1); 21 | res[0] = identity(); 22 | for (std::size_t i = 1; i <= maxN; ++i) { 23 | res[i] = res[i - 1] * static_cast(i); 24 | } 25 | return res; 26 | } 27 | 28 | template 29 | std::vector> binomials(std::size_t maxN) { 30 | std::vector> res(maxN + 1, std::vector(maxN + 1)); 31 | for (std::size_t n = 0; n <= maxN; ++n) { 32 | res[n][0] = identity(); 33 | res[n][n] = identity(); 34 | for (std::size_t k = 1; k < n; ++k) { 35 | res[n][k] = res[n - 1][k - 1] + res[n - 1][k]; 36 | } 37 | } 38 | 39 | return res; 40 | } 41 | 42 | template ::value>> 43 | T binomial(U n, U k) { 44 | if (k > n || k < 0) { 45 | return T(); 46 | } 47 | T res = identity(); 48 | for (U i: inclusiveRange(1, k)) { 49 | res *= n - i + 1; 50 | res /= i; 51 | } 52 | return res; 53 | }; 54 | 55 | template ::value>> 56 | std::vector pascalTriangleRow(U n, U k) { 57 | SPCPPL_ASSERT(k >= 0); 58 | std::vector result(k + 1); 59 | result[0] = identity(); 60 | for (U i: inclusiveRange(1, k)) { 61 | result[i] = result[i - 1] * (n - i + 1) / i; 62 | } 63 | return result; 64 | }; 65 | 66 | template ::value>> 67 | std::vector pascalTriangleRow(U n) { 68 | return pascalTriangleRow(n, n); 69 | }; 70 | 71 | template ::value>> 72 | T starsAndBars(U stars, U groups) { 73 | if (groups == 0) { 74 | if (stars == 0) { 75 | return identity(); 76 | } else { 77 | return T(); 78 | } 79 | } 80 | return binomial(stars + groups - 1, groups - 1); 81 | }; 82 | -------------------------------------------------------------------------------- /spcppl/numbers/phi.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | template 4 | T phi(T x) { 5 | T result = x; 6 | for (int i = 2; i * i <= x; ++i) { 7 | if (x % i == 0) { 8 | result /= i; 9 | result *= i - 1; 10 | while (x % i == 0) { 11 | x /= i; 12 | } 13 | } 14 | } 15 | if (x > 1) { 16 | result /= x; 17 | result *= x - 1; 18 | } 19 | return result; 20 | } -------------------------------------------------------------------------------- /spcppl/numbers/primes.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | inline bool isPrime(int n) { 11 | for (int i = 2; i * i <= n; ++i) { 12 | if (n % i == 0) { 13 | return false; 14 | } 15 | } 16 | return n >= 2; 17 | } 18 | 19 | inline bool isPrime(int64_t n) { 20 | for (int64_t i = 2; i * i <= n; ++i) { 21 | if (n % i == 0) { 22 | return false; 23 | } 24 | } 25 | return n >= 2; 26 | } 27 | 28 | inline std::vector primeMap(std::size_t maxN) { 29 | std::vector prime(maxN + 1, true); 30 | 31 | prime[0] = false; 32 | prime[1] = false; 33 | 34 | for (std::size_t i = 2; i * i <= maxN; ++i) { 35 | if (prime[i]) { 36 | if (i * 1ULL * i <= maxN) { 37 | for (std::size_t j = i * i; j <= maxN; j += i) { 38 | prime[j] = false; 39 | } 40 | } 41 | } 42 | } 43 | return prime; 44 | } 45 | 46 | inline std::vector allPrimes(int maxN) { 47 | std::vector result; 48 | result.reserve(maxN); 49 | std::vector map = primeMap(maxN); 50 | for (int i: range(maxN + 1)) { 51 | if (map[i]) { 52 | result.push_back(i); 53 | } 54 | } 55 | return result; 56 | } 57 | 58 | inline int nextPrime(int n) { 59 | while (!isPrime(n)) { 60 | ++n; 61 | } 62 | return n; 63 | } 64 | 65 | inline int64_t nextPrime(int64_t n) { 66 | while (!isPrime(n)) { 67 | ++n; 68 | } 69 | return n; 70 | } 71 | 72 | /* 73 | * It needs primes up to sqrt(r - 1) 74 | */ 75 | template 76 | std::vector primeMapOnRange(T l, T r, const std::vector& primes) { 77 | SPCPPL_ASSERT(l > 0); 78 | std::vector prime(static_cast(r - l), true); 79 | if (l == 1) { 80 | prime[0] = false; 81 | } 82 | for (int p: primes) { 83 | if (static_cast(p) * p > r) { 84 | break; 85 | } 86 | T start_idx = divideCeil(l, static_cast(p)); 87 | if (start_idx < 2) { 88 | start_idx = 2; 89 | } 90 | for (auto j = static_cast(start_idx * p - l); j < prime.size(); j += p) { 91 | prime[j] = false; 92 | } 93 | } 94 | return prime; 95 | } 96 | 97 | template 98 | std::vector primesOnRange(T l, T r, const std::vector& primes) { 99 | auto primeMap = primeMapOnRange(l, r, primes); 100 | std::vector result; 101 | for (std::size_t i = 0; i < primeMap.size(); ++i) { 102 | if (primeMap[i]) { 103 | result.push_back(static_cast(i + l)); 104 | } 105 | } 106 | return result; 107 | } 108 | -------------------------------------------------------------------------------- /spcppl/numbers/progression.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | template 6 | T geometricProgrssionSum(T first, T q, long long n) { 7 | if (q == 1) { 8 | return first * n; 9 | } 10 | return first * (1 - binpow(q, n)) / (1 - q); 11 | } 12 | 13 | template 14 | T inifiniteGeometricProgressionSum(T first, T q) { 15 | SPCPPL_ASSERT(-1 < q && q < 1); 16 | return first / (1 - q); 17 | } 18 | -------------------------------------------------------------------------------- /spcppl/parallel.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include "ranges/fors.hpp" 5 | 6 | template 7 | T workerStart(T all, int nodeId, int nodes) { 8 | SPCPPL_ASSERT(nodeId <= nodes); 9 | T everyone = all / nodes; 10 | T begin = everyone * nodeId; 11 | begin += std::min(static_cast(all % nodes), nodeId); 12 | return begin; 13 | } 14 | 15 | template 16 | IntegerRange workerRange(T all, int nodeId, int nodes) { 17 | return range(workerStart(all, nodeId, nodes), workerStart(all, nodeId + 1, nodes)); 18 | } -------------------------------------------------------------------------------- /spcppl/random/random.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | namespace impl { 7 | using Random = std::mt19937; 8 | } // namespace impl 9 | 10 | inline impl::Random& randomEngine() { 11 | static std::random_device device; 12 | static impl::Random engine(device()); 13 | return engine; 14 | } 15 | 16 | inline int randomInteger() { 17 | std::uniform_int_distribution d; 18 | return d(randomEngine()); 19 | } 20 | 21 | inline int randomInteger(int to) { 22 | SPCPPL_ASSERT(to > 0); 23 | std::uniform_int_distribution d(0, to - 1); 24 | return d(randomEngine()); 25 | } 26 | 27 | inline int randomInteger(int from, int to) { 28 | return from + randomInteger(to - from); 29 | } 30 | -------------------------------------------------------------------------------- /spcppl/ranges/Range.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | template 6 | class Range { 7 | public: 8 | Range(T begin, T end): begin_(std::move(begin)), end_(std::move(end)) { 9 | 10 | } 11 | 12 | T begin() const { 13 | return begin_; 14 | } 15 | 16 | T end() const { 17 | return end_; 18 | } 19 | 20 | private: 21 | T begin_; 22 | T end_; 23 | }; 24 | 25 | 26 | template 27 | Range make_range(T begin, T end) { 28 | return Range(begin, end); 29 | } 30 | -------------------------------------------------------------------------------- /spcppl/ranges/fors.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | /** 7 | * Support decrementing and multi-passing, but not declared bidirectional(or even forward) because 8 | * it's reference type is not a reference. 9 | * 10 | * It doesn't return reference because 11 | * 1. Anyway it'll not satisfy requirement [forward.iterators]/6 12 | * If a and b are both dereferenceable, then a == b if and only if *a and 13 | * b are bound to the same object. 14 | * 2. It'll not work with reverse_iterator that returns operator * of temporary which is temporary for this iterator 15 | * 16 | * Note, reverse_iterator is not guaranteed to work now too since it works only with bidirectional iterators, 17 | * but it's seems to work at least on my implementation. 18 | * 19 | * It's not really useful anywhere except iterating anyway. 20 | */ 21 | template 22 | class IntegerIterator { 23 | public: 24 | using value_type = T; 25 | using difference_type = std::ptrdiff_t; 26 | using pointer = T*; 27 | using reference = T; 28 | using iterator_category = std::input_iterator_tag; 29 | 30 | explicit IntegerIterator(T value): value(value) { 31 | 32 | } 33 | 34 | IntegerIterator& operator++() { 35 | ++value; 36 | return *this; 37 | } 38 | 39 | IntegerIterator operator++(int) { 40 | IntegerIterator copy = *this; 41 | ++value; 42 | return copy; 43 | } 44 | 45 | IntegerIterator& operator--() { 46 | --value; 47 | return *this; 48 | } 49 | 50 | IntegerIterator operator--(int) { 51 | IntegerIterator copy = *this; 52 | --value; 53 | return copy; 54 | } 55 | 56 | T operator*() const { 57 | return value; 58 | } 59 | 60 | bool operator==(IntegerIterator rhs) const { 61 | return value == rhs.value; 62 | } 63 | 64 | bool operator!=(IntegerIterator rhs) const { 65 | return !(*this == rhs); 66 | } 67 | 68 | private: 69 | T value; 70 | }; 71 | 72 | template 73 | class IntegerRange { 74 | public: 75 | IntegerRange(T begin, T end): begin_(begin), end_(end) { 76 | SPCPPL_ASSERT(begin <= end); 77 | } 78 | 79 | IntegerIterator begin() const { 80 | return IntegerIterator(begin_); 81 | } 82 | 83 | IntegerIterator end() const { 84 | return IntegerIterator(end_); 85 | } 86 | 87 | private: 88 | T begin_; 89 | T end_; 90 | }; 91 | 92 | template 93 | class ReversedIntegerRange { 94 | using IteratorType = std::reverse_iterator>; 95 | public: 96 | ReversedIntegerRange(T begin, T end): begin_(begin), end_(end) { 97 | SPCPPL_ASSERT(begin >= end); 98 | } 99 | 100 | IteratorType begin() const { 101 | return IteratorType(IntegerIterator(begin_)); 102 | } 103 | 104 | IteratorType end() const { 105 | return IteratorType(IntegerIterator(end_)); 106 | } 107 | 108 | private: 109 | T begin_; 110 | T end_; 111 | }; 112 | 113 | template 114 | IntegerRange range(T to) { 115 | return IntegerRange(0, to); 116 | } 117 | 118 | template 119 | IntegerRange range(T from, T to) { 120 | return IntegerRange(from, to); 121 | } 122 | 123 | template 124 | IntegerRange inclusiveRange(T to) { 125 | return IntegerRange(0, to + 1); 126 | } 127 | 128 | template 129 | IntegerRange inclusiveRange(T from, T to) { 130 | return IntegerRange(from, to + 1); 131 | } 132 | 133 | template 134 | ReversedIntegerRange downrange(T from) { 135 | return ReversedIntegerRange(from, 0); 136 | } 137 | 138 | template 139 | ReversedIntegerRange downrange(T from, T to) { 140 | return ReversedIntegerRange(from, to); 141 | } 142 | 143 | template 144 | ReversedIntegerRange inclusiveDownrange(T from) { 145 | return ReversedIntegerRange(from + 1, 0); 146 | } 147 | 148 | template 149 | ReversedIntegerRange inclusiveDownrange(T from, T to) { 150 | return ReversedIntegerRange(from + 1, to); 151 | } 152 | -------------------------------------------------------------------------------- /spcppl/ranges/indices.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | template 9 | std::vector indices(T n) { 10 | SPCPPL_ASSERT(n >= 0); 11 | std::vector v(static_cast(n)); 12 | for (T i: range(n)) { 13 | v[static_cast(i)] = i; 14 | } 15 | return v; 16 | } 17 | -------------------------------------------------------------------------------- /spcppl/ranges/pairwiseMerge.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | template 6 | void pairwiseMerge(Range& range, Function function) { 7 | auto output = range.begin(); 8 | auto end = range.end(); 9 | if (output == end) { 10 | return; 11 | } 12 | auto current = output; 13 | ++current; 14 | for (;current != end; ++current) { 15 | if (!function(*output, *current)) { 16 | ++output; 17 | *output = std::move(*current); 18 | } 19 | } 20 | 21 | ++output; 22 | range.erase(output, end); 23 | } 24 | -------------------------------------------------------------------------------- /spcppl/ranges/prefixSums.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | template 8 | auto prefixSums(const R& range) -> std::vector::value_type> { 9 | std::vector::value_type> result( 10 | static_cast( 11 | std::distance(std::begin(range), std::end(range)) + 1 12 | ) 13 | ); 14 | std::partial_sum(std::begin(range), std::end(range), result.begin() + 1); 15 | return result; 16 | } 17 | -------------------------------------------------------------------------------- /spcppl/ranges/range_iterator_traits.hpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | template 5 | using range_iterator_traits = std::iterator_traits().begin())>::type>; 6 | -------------------------------------------------------------------------------- /spcppl/ranges/wrappers.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include "fors.hpp" 6 | 7 | template 8 | void sort(R& range) { 9 | std::sort(range.begin(), range.end()); 10 | } 11 | 12 | template 13 | void sort(R& range, Comp comp) { 14 | std::sort(range.begin(), range.end(), comp); 15 | } 16 | 17 | template 18 | void reverse(R& range) { 19 | std::reverse(range.begin(), range.end()); 20 | } 21 | 22 | template 23 | auto lower_bound(const R& range, const T& value) -> decltype(range.begin()) { 24 | return std::lower_bound(range.begin(), range.end(), value); 25 | } 26 | 27 | template 28 | auto lower_bound(const R& range, const T& value, Comp comp) -> decltype(range.begin()) { 29 | return std::lower_bound(range.begin(), range.end(), value, comp); 30 | } 31 | 32 | template 33 | auto upper_bound(const R& range, const T& value) -> decltype(range.begin()) { 34 | return std::upper_bound(range.begin(), range.end(), value); 35 | } 36 | 37 | template 38 | auto upper_bound(const R& range, const T& value, Comp comp) -> decltype(range.begin()) { 39 | return std::upper_bound(range.begin(), range.end(), value, comp); 40 | } 41 | 42 | template 43 | auto min_element(const R& range) -> decltype(range.begin()) { 44 | return std::min_element(range.begin(), range.end()); 45 | } 46 | 47 | template 48 | auto max_element(const R& range) -> decltype(range.begin()) { 49 | return std::max_element(range.begin(), range.end()); 50 | } 51 | 52 | template 53 | bool next_permutation(R& range) { 54 | return std::next_permutation(range.begin(), range.end()); 55 | } 56 | 57 | template 58 | void unique(std::vector& range) { 59 | range.erase(std::unique(range.begin(), range.end()), range.end()); 60 | } 61 | 62 | template 63 | R sorted(R range) { 64 | sort(range); 65 | return range; 66 | } 67 | 68 | template 69 | R sorted(R range, Comp comp) { 70 | sort(range, comp); 71 | return range; 72 | } 73 | 74 | template 75 | R reversed(R range) { 76 | reverse(range); 77 | return range; 78 | } 79 | -------------------------------------------------------------------------------- /spcppl/strings/SuffixArray.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | class SuffixArray { 12 | public: 13 | explicit SuffixArray(std::string s) { 14 | s += '\0'; 15 | suffArray.resize(s.size()); 16 | std::vector head(std::max(s.size(), static_cast(128)), 0); 17 | std::vector color(s.size()); 18 | for (char c: s) { 19 | SPCPPL_ASSERT(c >= 0); 20 | ++head[c]; 21 | } 22 | for (int i = 1; i < 128; ++i) { 23 | head[i] += head[i - 1]; 24 | } 25 | for (int i = 127; i > 0; --i) { 26 | head[i] = head[i - 1]; 27 | } 28 | head[0] = 0; 29 | for (auto i: range(s.size())) { 30 | suffArray[head[s[i]]] = i; 31 | ++head[s[i]]; 32 | } 33 | std::size_t numberOfClasses = 1; 34 | head[0] = 0; 35 | for (auto i: range(static_cast(1), s.size())) { 36 | if (s[suffArray[i - 1]] != s[suffArray[i]]) { 37 | ++numberOfClasses; 38 | head[numberOfClasses - 1] = i; 39 | } 40 | color[suffArray[i]] = numberOfClasses - 1; 41 | } 42 | 43 | std::vector nextSufArray(s.size()); 44 | std::vector nextColor(s.size()); 45 | for (std::size_t k = 1; k < s.size(); k *= 2) { 46 | for (auto suffix: suffArray) { 47 | std::size_t firstPartBeginning = suffix - k; 48 | if (suffix < k) { 49 | firstPartBeginning += s.size(); 50 | } 51 | nextSufArray[head[color[firstPartBeginning]]] = firstPartBeginning; 52 | ++head[color[firstPartBeginning]]; 53 | } 54 | swap(suffArray, nextSufArray); 55 | 56 | std::size_t secondPartBeginning; 57 | std::pair prevSuffClasses; 58 | std::pair curSuffClasses {color.size(), 0}; 59 | numberOfClasses = 0; 60 | 61 | for (auto pos: range(suffArray.size())) { 62 | prevSuffClasses = curSuffClasses; 63 | 64 | secondPartBeginning = suffArray[pos] + k; 65 | if (secondPartBeginning >= s.size()) { 66 | secondPartBeginning -= s.size(); 67 | } 68 | curSuffClasses = std::make_pair(color[suffArray[pos]], color[secondPartBeginning]); 69 | 70 | if (curSuffClasses != prevSuffClasses) { 71 | ++numberOfClasses; 72 | head[numberOfClasses - 1] = pos; 73 | } 74 | nextColor[suffArray[pos]] = numberOfClasses - 1; 75 | } 76 | 77 | swap(color, nextColor); 78 | 79 | if (numberOfClasses == s.size()) 80 | break; 81 | } 82 | suffArray.erase(suffArray.begin()); 83 | 84 | pos.resize(suffArray.size()); 85 | for (std::size_t i = 0; i < suffArray.size(); ++i) { 86 | pos[suffArray[i]] = i; 87 | } 88 | } 89 | 90 | std::size_t getNthSuffix(std::size_t n) const { 91 | SPCPPL_ASSERT(n < suffArray.size()); 92 | return suffArray[n]; 93 | } 94 | 95 | std::size_t getPosition(std::size_t suffix) const { 96 | SPCPPL_ASSERT(suffix < suffArray.size()); 97 | return pos[suffix]; 98 | } 99 | 100 | std::size_t size() const { 101 | return pos.size(); 102 | } 103 | 104 | private: 105 | std::vector suffArray; 106 | std::vector pos; 107 | }; 108 | 109 | class SuffixArrayWithLcp : public SuffixArray { 110 | public: 111 | explicit SuffixArrayWithLcp(const std::string& s): 112 | SuffixArray(s), 113 | sparse(generateLCP(*this, s)) { 114 | 115 | } 116 | std::size_t lcp(std::size_t l, std::size_t r) { 117 | l = getPosition(l); 118 | r = getPosition(r); 119 | auto p = std::minmax(l, r); 120 | return lcpByPosition(p.first, p.second); 121 | } 122 | 123 | std::size_t lcpByPosition(std::size_t l, std::size_t r) { 124 | SPCPPL_ASSERT(l <= r && r < size()); 125 | if (l == r) { 126 | return size() - getNthSuffix(l); 127 | } 128 | return sparse.getResult(l, r); 129 | } 130 | 131 | private: 132 | static std::vector generateLCP(const SuffixArray& base, const std::string& s) { 133 | std::size_t curLcp = 0; 134 | 135 | std::vector lcp(s.size() - 1); 136 | for (std::size_t i = 0; i < s.size(); ++i) { 137 | std::size_t position = base.getPosition(i); 138 | if (position == s.size() - 1) { 139 | curLcp = 0; 140 | continue; 141 | } 142 | 143 | while (s[i + curLcp] == s[base.getNthSuffix(position + 1) + curLcp]) { 144 | ++curLcp; 145 | } 146 | lcp[position] = curLcp; 147 | 148 | if (curLcp > 0) 149 | --curLcp; 150 | } 151 | return lcp; 152 | } 153 | SparseTable sparse; 154 | }; 155 | -------------------------------------------------------------------------------- /spcppl/strings/hash/OverflowHasher.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | class OverflowHasher { 8 | public: 9 | static const unsigned long long multiplier = 97; 10 | 11 | OverflowHasher(const std::string& s): hashes(s.size() + 1) { 12 | ensureLength(s.length()); 13 | for (std::size_t i: range(s.size())) { 14 | hashes[i + 1] = hashes[i] * multiplier + s[i]; 15 | } 16 | } 17 | 18 | unsigned long long hash(std::size_t from, std::size_t to) const { 19 | SPCPPL_ASSERT(from <= to); 20 | return hashes[to] - hashes[from] * powers[to - from]; 21 | } 22 | 23 | private: 24 | 25 | static void ensureLength(std::size_t length) { 26 | powers.reserve(length + 1); 27 | while (powers.size() < length + 1) { 28 | powers.push_back(powers.back() * multiplier); 29 | } 30 | } 31 | 32 | static std::vector powers; 33 | std::vector hashes; 34 | }; 35 | 36 | std::vector OverflowHasher::powers = {1}; 37 | -------------------------------------------------------------------------------- /spcppl/strings/hash/StringHash.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | template 9 | class StringHash { 10 | public: 11 | StringHash(std::string s): hasher(s), s(std::move(s)) { 12 | 13 | } 14 | 15 | uint64_t hash(std::size_t from, std::size_t to) const { 16 | return hasher.hash(from, to); 17 | } 18 | 19 | uint64_t prefixHash(std::size_t to) const { 20 | return hasher.hash(0, to); 21 | } 22 | 23 | uint64_t suffixHash(std::size_t from) const { 24 | return hasher.hash(from, s.size()); 25 | } 26 | 27 | uint64_t hash() const { 28 | return hasher.hash(0, s.size()); 29 | } 30 | 31 | bool less(std::size_t l1, std::size_t r1, std::size_t l2, std::size_t r2) { 32 | SPCPPL_ASSERT(l1 <= r1 && l2 <= r2); 33 | std::size_t min_len = std::min(r1 - l1, r2 - l2); 34 | if (s[l1] != s[l2]) { 35 | return s[l1] < s[l2]; 36 | } 37 | if (hash(l1, l1 + min_len) == hash(l2, l2 + min_len)) { 38 | return r2 - l2 > r1 - l1; 39 | } 40 | std::size_t l = 0, r = min_len; 41 | while(r - l > 1) { 42 | std::size_t m = (r + l) / 2; 43 | if (hash(l1, l1 + m) == hash(l2, l2 + m)) { 44 | l = m; 45 | } else { 46 | r = m; 47 | } 48 | } 49 | 50 | auto res2 = s[l1 + l] < s[l2 + l]; 51 | return res2; 52 | } 53 | 54 | private: 55 | Hasher hasher; 56 | std::string s; 57 | }; 58 | -------------------------------------------------------------------------------- /spcppl/strings/hash/TwoIntsHasher.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | class TwoIntsHasher { 12 | public: 13 | 14 | TwoIntsHasher(const std::string& s) { 15 | ensureLength(s.length()); 16 | for (std::size_t j = 0; j < 2; ++j) { 17 | hashes[j].resize(s.length() + 1); 18 | for (std::size_t i: range(s.size())) { 19 | hashes[j][i + 1] = (hashes[j][i] * multipliers[j] + static_cast(s[i])); 20 | } 21 | } 22 | } 23 | 24 | uint64_t hash(std::size_t from, std::size_t to) const { 25 | SPCPPL_ASSERT(from <= to); 26 | return (oneHash(from, to, 0) << 32ULL) | (oneHash(from, to, 1)); 27 | } 28 | 29 | private: 30 | struct Modulo { 31 | static int value; 32 | }; 33 | using Z = Zn; 34 | 35 | uint64_t oneHash(std::size_t from, std::size_t to, std::size_t index) const { 36 | return static_cast((hashes[index][to] - hashes[index][from] * powers[index][to - from]).intValue()); 37 | } 38 | 39 | static void ensureLength(std::size_t length) { 40 | for (std::size_t i = 0; i < 2; ++i) { 41 | std::vector& powersArray = powers[i]; 42 | powersArray.reserve(length + 1); 43 | while (powersArray.size() < length + 1) { 44 | powersArray.push_back(powersArray.back() * multipliers[i]); 45 | } 46 | } 47 | } 48 | 49 | static std::array, 2> powers; 50 | std::array, 2> hashes; 51 | 52 | static int32_t randomBigPrime() { 53 | return nextPrime(randomInteger(1000000000, 2000000000)); 54 | } 55 | 56 | static const std::array multipliers; 57 | }; 58 | 59 | int TwoIntsHasher::Modulo::value = randomBigPrime(); 60 | std::array, 2> TwoIntsHasher::powers = {{{TwoIntsHasher::Z::rawValueOf(1)}, {TwoIntsHasher::Z::rawValueOf(1)}}}; 61 | 62 | const std::array TwoIntsHasher::multipliers = {{TwoIntsHasher::Z::rawValueOf(137), TwoIntsHasher::Z::rawValueOf(97)}}; 63 | -------------------------------------------------------------------------------- /spcppl/strings/prefixFunction.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | std::vector prefixFunction(const std::string& s) { 9 | auto n = s.size(); 10 | std::vector pi(n); 11 | for (auto i: range(1, n)) { 12 | std::size_t j = pi[i - 1]; 13 | while (j > 0 && s[i] != s[j]) { 14 | j = pi[j - 1]; 15 | } 16 | if (s[i] == s[j]) { 17 | ++j; 18 | } 19 | pi[i] = j; 20 | } 21 | return pi; 22 | } 23 | 24 | /** 25 | * Doesn't work with string containing null bytes 26 | */ 27 | bool isSubstring(const std::string& haystack, const std::string& needle) { 28 | auto pi = prefixFunction(needle + '\0' + haystack); 29 | for (auto value: pi) { 30 | if (value == needle.size()) { 31 | return true; 32 | } 33 | } 34 | return false; 35 | } 36 | -------------------------------------------------------------------------------- /spcppl/typeTraits/Disjunction.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | // todo[c++17]: replace with std::disjunction_v 6 | template 7 | struct Disjunction : std::false_type { 8 | }; 9 | 10 | template 11 | // todo[c++14] use bool_constant 12 | struct Disjunction : std::integral_constant::value> { 13 | 14 | }; 15 | 16 | #if __cplusplus >= 201703L 17 | template 18 | constexpr bool DisjunctionV = Disjunction::value; 19 | 20 | static_assert(!DisjunctionV<>, ""); 21 | static_assert(!DisjunctionV, ""); 22 | static_assert(DisjunctionV, ""); 23 | static_assert(DisjunctionV, ""); 24 | static_assert(DisjunctionV, ""); 25 | static_assert(DisjunctionV, ""); 26 | #endif -------------------------------------------------------------------------------- /spcppl/typeTraits/IsContainer.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | template 7 | constexpr auto hasBegin(int) -> decltype(std::begin(std::declval()), true) { 8 | return true; 9 | } 10 | 11 | template 12 | constexpr bool hasBegin(...) { 13 | return false; 14 | } 15 | 16 | template 17 | using IsContainer = std::integral_constant(0)>; 18 | -------------------------------------------------------------------------------- /spcppl/typeTraits/IsOneOf.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | template 7 | // todo[c++17] use is_same_v 8 | // todo[c++17] use variable template 9 | using IsOneOf = Disjunction::value...>; 10 | -------------------------------------------------------------------------------- /spcppl/typeTraits/IsSaneInteger.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | //todo[c++14] use remove_cv_t 7 | //todo[c++17] use is_integral_v 8 | //todo[c++17] use variable template 9 | template 10 | using IsSaneInteger = std::integral_constant< 11 | bool, 12 | std::is_integral::value && !IsOneOf::type, char, signed char, unsigned char, bool, char16_t, char32_t, wchar_t>::value 13 | >; 14 | -------------------------------------------------------------------------------- /spcppl/typeTraits/enable_if_t.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | template 6 | //todo[c++14] use std::enable_if_t 7 | using enable_if_t = typename std::enable_if::type; 8 | -------------------------------------------------------------------------------- /spcppl/updateMin.hpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | template 4 | bool updateMin(T& oldValue, const T& newValue) { 5 | if (newValue < oldValue) { 6 | oldValue = newValue; 7 | return true; 8 | } 9 | return false; 10 | } 11 | 12 | template 13 | bool updateMax(T& oldValue, const T& newValue) { 14 | if (oldValue < newValue) { 15 | oldValue = newValue; 16 | return true; 17 | } 18 | return false; 19 | } 20 | -------------------------------------------------------------------------------- /tests/CoordinateMinimizer.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | TEST(CoordinateMinimizer, Basic) { 7 | std::vector v{10, 7, 12}; 8 | CoordinateMinimizer minimizer(v); 9 | ASSERT_EQ(minimizer.find(7), static_cast(0)); 10 | ASSERT_EQ(minimizer.find(12), static_cast(2)); 11 | ASSERT_EQ(minimizer.find(10), static_cast(1)); 12 | } 13 | 14 | TEST(CoordinateMinimizer, Stings) { 15 | std::vector v{"abc", "zzz", "z", "x"}; 16 | CoordinateMinimizer minimizer(v); 17 | ASSERT_EQ(minimizer.find("abc"), static_cast(0)); 18 | ASSERT_EQ(minimizer.find("x"), static_cast(1)); 19 | ASSERT_EQ(minimizer.find("z"), static_cast(2)); 20 | ASSERT_EQ(minimizer.find("zzz"), static_cast(3)); 21 | } 22 | 23 | TEST(CoordinateMinimizer, OneByOne) { 24 | CoordinateMinimizer minimizer; 25 | minimizer.add(5); 26 | minimizer.add(3); 27 | minimizer.add(10); 28 | minimizer.finalize(); 29 | ASSERT_EQ(minimizer.find(3), static_cast(0)); 30 | ASSERT_EQ(minimizer.find(5), static_cast(1)); 31 | ASSERT_EQ(minimizer.find(10), static_cast(2)); 32 | } 33 | -------------------------------------------------------------------------------- /tests/DSU.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | TEST(DSU, Basics) { 5 | DSU dsu(5); 6 | dsu.unite(3, 1); 7 | dsu.unite(3, 4); 8 | 9 | ASSERT_EQ(dsu.getSet(1), dsu.getSet(3)); 10 | ASSERT_EQ(dsu.getSet(1), dsu.getSet(4)); 11 | ASSERT_NE(dsu.getSet(3), dsu.getSet(0)); 12 | ASSERT_NE(dsu.getSet(3), dsu.getSet(2)); 13 | ASSERT_NE(dsu.getSet(0), dsu.getSet(2)); 14 | } 15 | 16 | TEST(DSU, Immidiate) { 17 | DSU dsu(3); 18 | ASSERT_EQ(dsu.getSet(0), static_cast(0)); 19 | ASSERT_EQ(dsu.getSet(1), static_cast(1)); 20 | ASSERT_EQ(dsu.getSet(2), static_cast(2)); 21 | } 22 | 23 | TEST(DSU, ComponentCount) { 24 | DSU dsu(5); 25 | ASSERT_EQ(dsu.components(), static_cast(5)); 26 | dsu.unite(1, 2); 27 | dsu.unite(2, 3); 28 | ASSERT_EQ(dsu.components(), static_cast(3)); 29 | dsu.unite(1, 3); 30 | ASSERT_EQ(dsu.components(), static_cast(3)); 31 | } 32 | 33 | TEST(DSU, MergeResult) { 34 | DSU dsu(5); 35 | EXPECT_TRUE(dsu.unite(1, 3)); 36 | EXPECT_TRUE(dsu.unite(3, 4)); 37 | EXPECT_FALSE(dsu.unite(1, 4)); 38 | } 39 | -------------------------------------------------------------------------------- /tests/Matrix.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include "detectionIdiom.hpp" 6 | 7 | namespace { 8 | MAKE_CONSTANT(N, std::size_t) 9 | MAKE_CONSTANT(M, std::size_t) 10 | } 11 | 12 | using RectangularMatrix = FixedSizeMatrix; 13 | using SquareMatrix = FixedSizeMatrix; 14 | using RuntimeMatrix = Matrix; 15 | 16 | TEST(Matrix, CreationDefault) { 17 | RectangularMatrix matrix; 18 | ASSERT_EQ(matrix.rows(), static_cast(2)); 19 | ASSERT_EQ(matrix.columns(), static_cast(3)); 20 | for (std::size_t i = 0; i < matrix.rows(); ++i) { 21 | for (std::size_t j = 0; j < matrix.columns(); ++j) { 22 | ASSERT_EQ(matrix[i][j], 0) << "i: " << i << " j: " << j; 23 | } 24 | } 25 | } 26 | 27 | TEST(Matrix, CreationFromValue) { 28 | SquareMatrix matrix{5}; 29 | ASSERT_EQ(matrix.rows(), static_cast(2)); 30 | ASSERT_EQ(matrix.columns(), static_cast(2)); 31 | for (std::size_t i = 0; i < matrix.rows(); ++i) { 32 | for (std::size_t j = 0; j < matrix.columns(); ++j) { 33 | ASSERT_EQ(matrix[i][j], 5) << "i: " << i << " j: " << j; 34 | } 35 | } 36 | } 37 | 38 | TEST(Matrix, CreationRuntime) { 39 | for (std::size_t i = 1; i < 5; ++i) { 40 | for (std::size_t j = 1; j < 5; ++j) { 41 | N::value = i; 42 | M::value = j; 43 | RuntimeMatrix matrix; 44 | ASSERT_EQ(matrix.rows(), static_cast(i)); 45 | ASSERT_EQ(matrix.columns(), static_cast(j)); 46 | } 47 | } 48 | } 49 | 50 | TEST(Matrix, Add) { 51 | RectangularMatrix lhs; 52 | RectangularMatrix rhs; 53 | lhs[0][0] = 1; 54 | lhs[0][1] = 2; 55 | lhs[1][2] = 3; 56 | 57 | rhs[0][1] = 42; 58 | rhs[1][1] = 5; 59 | 60 | auto sum = lhs + rhs; 61 | static_assert(std::is_same::value, "Wrong size"); 62 | 63 | ASSERT_EQ(sum[0][0], 1); 64 | ASSERT_EQ(sum[0][1], 44); 65 | ASSERT_EQ(sum[0][2], 0); 66 | ASSERT_EQ(sum[1][0], 0); 67 | ASSERT_EQ(sum[1][1], 5); 68 | ASSERT_EQ(sum[1][2], 3); 69 | } 70 | 71 | TEST(Matrix, Identity) { 72 | auto id = identity(); 73 | ASSERT_EQ(id[0][0], 1); 74 | ASSERT_EQ(id[0][1], 0); 75 | ASSERT_EQ(id[1][0], 0); 76 | ASSERT_EQ(id[1][1], 1); 77 | 78 | SquareMatrix matrix; 79 | matrix[0][0] = 1; 80 | matrix[0][1] = 2; 81 | matrix[1][0] = 5; 82 | matrix[1][1] = 94; 83 | 84 | ASSERT_EQ(matrix * id, matrix); 85 | ASSERT_EQ(id * matrix, matrix); 86 | } 87 | 88 | TEST(Matrix, Transpose) { 89 | FixedSizeMatrix matrix; 90 | matrix[0][0] = 1; 91 | matrix[0][1] = 5; 92 | matrix[0][2] = 6; 93 | matrix[1][0] = 2; 94 | matrix[1][1] = 0; 95 | matrix[1][2] = -1; 96 | 97 | auto transposed = matrix.transposed(); 98 | static_assert(std::is_same>::value); 99 | 100 | ASSERT_EQ(transposed[0][0], 1); 101 | ASSERT_EQ(transposed[0][1], 2); 102 | ASSERT_EQ(transposed[1][0], 5); 103 | ASSERT_EQ(transposed[1][1], 0); 104 | ASSERT_EQ(transposed[2][0], 6); 105 | ASSERT_EQ(transposed[2][1], -1); 106 | } 107 | 108 | TEST(Matrix, Multiplication) { 109 | SquareMatrix square1; 110 | SquareMatrix square2; 111 | 112 | square1[0][0] = 5; 113 | square1[0][1] = 1; 114 | square1[1][0] = 8; 115 | square1[1][1] = 12; 116 | 117 | square2[0][0] = 9; 118 | square2[0][1] = 3; 119 | square2[1][0] = 5; 120 | square2[1][1] = 4; 121 | 122 | SquareMatrix product = square1 * square2; 123 | ASSERT_EQ(product[0][0], 50); 124 | ASSERT_EQ(product[0][1], 19); 125 | ASSERT_EQ(product[1][0], 132); 126 | ASSERT_EQ(product[1][1], 72); 127 | } 128 | 129 | template 130 | using multiply = decltype(std::declval() * std::declval()); 131 | 132 | template 133 | using multiply_assign = decltype(std::declval() *= std::declval()); 134 | 135 | TEST(Matrix, MultiplicationCompilation) { 136 | ASSERT_TRUE((is_detected_v)); 137 | ASSERT_FALSE((is_detected_v)); 138 | ASSERT_TRUE((is_detected_v)); 139 | ASSERT_FALSE((is_detected_v)); 140 | 141 | M::value = 2; 142 | N::value = 2; 143 | ASSERT_FALSE((is_detected_v)); 144 | ASSERT_FALSE((is_detected_v)); 145 | 146 | ASSERT_TRUE((is_detected_exact_v)); 147 | ASSERT_TRUE((is_detected_exact_v, multiply, decltype(RectangularMatrix().transposed()), RectangularMatrix>)); 148 | 149 | ASSERT_TRUE((is_detected_v)); 150 | ASSERT_TRUE((is_detected_v>)); 151 | ASSERT_FALSE((is_detected_v)); 152 | ASSERT_FALSE((is_detected_v)); 153 | ASSERT_FALSE((is_detected_v)); 154 | } 155 | -------------------------------------------------------------------------------- /tests/binpow.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | TEST(Binpow, Ints) { 5 | ASSERT_EQ(binpow(2, 5), 32); 6 | ASSERT_EQ(binpow(0, 10), 0); 7 | ASSERT_EQ(binpow(1, 43), 1); 8 | ASSERT_EQ(binpow(-3, 3), -27); 9 | ASSERT_EQ(binpow(-1, 1000), 1); 10 | } 11 | 12 | struct Int { 13 | int x; 14 | Int operator *= (Int rhs) { 15 | x += rhs.x; 16 | return *this; 17 | } 18 | }; 19 | 20 | template <> 21 | struct IdentityHelper { 22 | static Int identity() { 23 | return {0}; 24 | } 25 | }; 26 | 27 | TEST(Binpow, Custom) { 28 | ASSERT_EQ(binpow(Int{3}, 5).x, 15); 29 | ASSERT_EQ(binpow(Int{9}, 3).x, 27); 30 | ASSERT_EQ(binpow(Int{9}, 0).x, 0); 31 | } 32 | 33 | -------------------------------------------------------------------------------- /tests/convolution.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | TEST(Convolution, Small) { 6 | std::vector v(8); 7 | v[2] = 10; 8 | v[5] = 1; 9 | v[3] = 3; 10 | std::vector expectedAnswer(8); 11 | expectedAnswer[2] = 10; 12 | expectedAnswer[3] = 3 + 10; 13 | expectedAnswer[5] = 1; 14 | expectedAnswer[6] = 10; 15 | expectedAnswer[7] = 3 + 1 + 10; 16 | ASSERT_EQ(submasksSums(v), expectedAnswer); 17 | } 18 | 19 | std::vector submasksSumsStupid(const std::vector& v) { 20 | std::vector results(v.size()); 21 | for (std::size_t i = 0; i < v.size(); ++i) { 22 | for (std::size_t j = 0; j < v.size(); ++j) { 23 | if ((i & j) == j) { 24 | results[i] += v[j]; 25 | } 26 | } 27 | } 28 | return results; 29 | } 30 | 31 | TEST(Convolution, Big) { 32 | std::mt19937 gen; 33 | std::vector input(1 << 10); 34 | std::uniform_int_distribution dist(-100, 100); 35 | for (std::size_t i = 0; i < (1 << 10); ++i) { 36 | input[i] = dist(gen); 37 | } 38 | 39 | ASSERT_EQ(submasksSums(input), submasksSumsStupid(input)); 40 | } 41 | -------------------------------------------------------------------------------- /tests/dataStructures/MinQueue.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include "tests/operator_size.hpp" 8 | 9 | TEST(MinQueueTest, ReturnsOnlyElement) { 10 | MinQueue queue; 11 | queue.push(42); 12 | EXPECT_EQ(queue.getMinimum(), 42); 13 | } 14 | 15 | TEST(MinQueueTest, ReturnCorrectSize) { 16 | MinQueue queue; 17 | EXPECT_EQ(queue.size(), 0_size); 18 | queue.push(7); 19 | EXPECT_EQ(queue.size(), 1_size); 20 | queue.push(3); 21 | EXPECT_EQ(queue.size(), 2_size); 22 | queue.push(99); 23 | EXPECT_EQ(queue.size(), 3_size); 24 | queue.pop(); 25 | EXPECT_EQ(queue.size(), 2_size); 26 | } 27 | 28 | TEST(MinQueueTest, ReturnsSmallestElement) { 29 | MinQueue queue; 30 | queue.push(15); 31 | EXPECT_EQ(queue.getMinimum(), 15); 32 | queue.push(7); 33 | EXPECT_EQ(queue.getMinimum(), 7); 34 | queue.push(8); 35 | EXPECT_EQ(queue.getMinimum(), 7); 36 | queue.pop(); 37 | EXPECT_EQ(queue.getMinimum(), 7); 38 | queue.pop(); 39 | EXPECT_EQ(queue.getMinimum(), 8); 40 | } 41 | 42 | TEST(MinQueueTest, StressTest) { 43 | MinQueue min_queue; 44 | std::deque std_queue; 45 | 46 | for (auto _: range(100000)) { 47 | static_cast(_); 48 | bool push = std_queue.empty() || randomInteger(2) == 0; 49 | if (push) { 50 | int value = randomInteger(); 51 | min_queue.push(value); 52 | std_queue.push_back(value); 53 | } else { 54 | min_queue.pop(); 55 | std_queue.pop_front(); 56 | } 57 | ASSERT_EQ(min_queue.size(), std_queue.size()); 58 | if (min_queue.size() > 0) { 59 | ASSERT_EQ( 60 | min_queue.getMinimum(), 61 | *std::min_element(std_queue.begin(), std_queue.end()) 62 | ); 63 | } 64 | } 65 | } 66 | 67 | TEST(MinQueueTest, ReturnsMaxElementWithGreater) { 68 | MinQueue> queue; 69 | queue.push(15); 70 | EXPECT_EQ(queue.getMinimum(), 15); 71 | queue.push(7); 72 | EXPECT_EQ(queue.getMinimum(), 15); 73 | queue.push(8); 74 | EXPECT_EQ(queue.getMinimum(), 15); 75 | queue.pop(); 76 | EXPECT_EQ(queue.getMinimum(), 8); 77 | queue.pop(); 78 | EXPECT_EQ(queue.getMinimum(), 8); 79 | } 80 | 81 | TEST(MinQueueTest, WorksWithMovyOnlyTypes) { 82 | MinQueue> queue; 83 | queue.push(std::make_unique(3)); 84 | queue.push(std::make_unique(7)); 85 | static_cast(queue.getMinimum()); 86 | queue.pop(); 87 | queue.pop(); 88 | } 89 | -------------------------------------------------------------------------------- /tests/dataStructures/NDArray.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | TEST(NDArrayTest, Creation) { 5 | NDArray array({{3, 5}}, 0); 6 | EXPECT_EQ(array[0][1], 0); 7 | } 8 | 9 | TEST(NDArrayTest, Assignment) { 10 | NDArray array({{3, 5}}, 0); 11 | EXPECT_EQ(array[2][1], 0); 12 | 13 | array[2][1] = 1; 14 | 15 | EXPECT_EQ(array[0][0], 0); 16 | EXPECT_EQ(array[2][1], 1); 17 | } 18 | 19 | TEST(NDArrayTest, FrontBackTest) { 20 | NDArray array({{3, 5, 7}}, 1); 21 | array.back().front().back() = 5; 22 | EXPECT_EQ(array[2][0][6], 5); 23 | 24 | EXPECT_EQ(&array.back().front().back(), &array[2][0][6]); 25 | 26 | EXPECT_EQ(&array[1].back()[4], &array[1][4][4]); 27 | } 28 | 29 | TEST(NDArrayTest, AssignViewTest) { 30 | NDArray array({{3, 2}}, 0); 31 | array[0][0] = 1; 32 | array[0][1] = 2; 33 | array[1][0] = 3; 34 | array[1][1] = 4; 35 | array[2][0] = 5; 36 | array[2][1] = 6; 37 | 38 | assignView(array[2], array[1]); 39 | 40 | EXPECT_EQ(array[2][0], 3); 41 | EXPECT_EQ(array[2][1], 4); 42 | EXPECT_EQ(array[0][0], 1); 43 | EXPECT_EQ(array[0][1], 2); 44 | EXPECT_EQ(array[1][0], 3); 45 | EXPECT_EQ(array[1][1], 4); 46 | } 47 | 48 | TEST(NDArrayTest, CreateArrayTest) { 49 | auto array = makeArray(5, 7, 2); 50 | EXPECT_EQ(array[3][2][1], 0); 51 | EXPECT_EQ(&array.back().back().back() - &array.front().front().front(), 5 * 7 * 2 - 1); 52 | 53 | auto filledArray = makeFilledArray(42, 3, 2, 8); 54 | 55 | EXPECT_EQ(filledArray[1][1][1], 42); 56 | EXPECT_EQ(&filledArray.back().back().back() - &filledArray.front().front().front(), 3 * 2 * 8 - 1); 57 | } 58 | -------------------------------------------------------------------------------- /tests/dataStructures/SparseTable.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | TEST(SparseTableTest, GetMinimumCorrectly) { 8 | std::vector elements {5, 3, 2, 7, 4}; 9 | SparseTable sparse(elements); 10 | 11 | EXPECT_EQ(sparse.getResult(2, 5), 2); 12 | EXPECT_EQ(sparse.getResult(0, 2), 3); 13 | EXPECT_EQ(sparse.getResult(3, 4), 7); 14 | } 15 | 16 | TEST(SparseTableTest, WorksWithNonStandardOperatoins) { 17 | struct GCD { 18 | int operator() (int a, int b) const { 19 | return gcd(a, b); 20 | } 21 | }; 22 | std::vector elements = {8, 5, 15, 9, 12}; 23 | SparseTable sparse(elements); 24 | EXPECT_EQ(sparse.getResult(2, 5), 3); 25 | EXPECT_EQ(sparse.getResult(0, 1), 8); 26 | EXPECT_EQ(sparse.getResult(0, 5), 1); 27 | EXPECT_EQ(sparse.getResult(0, 0), 0); 28 | } 29 | 30 | TEST(SparseTable, WorksWithEmptyRanges) { 31 | std::vector elements = {}; 32 | SparseTable sparse(elements, Min(), PositiveInfinity()()); 33 | EXPECT_EQ(sparse.getResult(0, 0), PositiveInfinity()()); 34 | } 35 | 36 | TEST(SparseTable, WorksWithSingleton) { 37 | SparseTable sparse({1}); 38 | 39 | EXPECT_EQ(sparse.getResult(0, 1), 1); 40 | } 41 | -------------------------------------------------------------------------------- /tests/dataStructures/TreapMultiset.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | TEST(TreapMultisetTest, IndexingInSortedOrder) { 5 | TreapMultiset set; 6 | set.insert(3); 7 | set.insert(7); 8 | set.insert(1); 9 | 10 | ASSERT_EQ(set.size(), static_cast(3)); 11 | 12 | EXPECT_EQ(set[0], 1); 13 | EXPECT_EQ(set[1], 3); 14 | EXPECT_EQ(set[2], 7); 15 | } 16 | 17 | TEST(TreapMultisetTest, HandlesSameArgumentsCorrectly) { 18 | TreapMultiset set; 19 | set.insert(5); 20 | set.insert(5); 21 | set.insert(1); 22 | 23 | EXPECT_EQ(set.size(), static_cast(3)); 24 | 25 | set.erase_one(5); 26 | 27 | ASSERT_EQ(set.size(), static_cast(2)); 28 | EXPECT_EQ(set[0], 1); 29 | EXPECT_EQ(set[1], 5); 30 | } 31 | 32 | TEST(TreapMultisetTest, HandlesMoveOnlyType) { 33 | TreapMultiset> set; 34 | set.insert(std::make_unique(5)); 35 | EXPECT_EQ(*set[0], 5); 36 | } 37 | 38 | TEST(TreapMultisetTest, HandlesImmovableType) { 39 | TreapMultiset> set; 40 | set.emplace(); 41 | } 42 | -------------------------------------------------------------------------------- /tests/dataStructures/segmentTree/BottomUpMaxSegmentTree.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | TEST(BottomUpMaxSegmentTree, CreationFromNumber) { 6 | BottomUpMaxSegmentTree tree(5); 7 | EXPECT_EQ(tree.getElement(3), NegativeInfinity()()); 8 | } 9 | 10 | TEST(BottomUpMaxSegmentTree, CreationFromList) { 11 | BottomUpMaxSegmentTree tree(std::vector{1, 3, 2, 5, 4}); 12 | EXPECT_EQ(tree.getResult(1, 3), 3); 13 | EXPECT_EQ(tree.getResult(0, 5), 5); 14 | EXPECT_EQ(tree.getElement(0), 1); 15 | } 16 | 17 | TEST(BottomUpMaxSegmentTree, FindFirstMinimum) { 18 | BottomUpMaxSegmentTree tree(std::vector{3, 2, 3, 8, 2}); 19 | EXPECT_EQ(tree.getResult(0, 5), 8); 20 | EXPECT_EQ(tree.getFirstMaximum(), 3u); 21 | 22 | tree.set(2, 8); 23 | EXPECT_EQ(tree.getFirstMaximum(), 2u); 24 | 25 | tree.set(4, 10); 26 | EXPECT_EQ(tree.getFirstMaximum(), 4u); 27 | } 28 | -------------------------------------------------------------------------------- /tests/dataStructures/segmentTree/BottomUpMinSegmentTree.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | TEST(BottomUpMinSegmentTree, CreationFromNumber) { 6 | BottomUpMinSegmentTree tree(5); 7 | EXPECT_EQ(tree.getElement(3), PositiveInfinity()()); 8 | } 9 | 10 | TEST(BottomUpMinSegmentTree, CreationFromList) { 11 | BottomUpMinSegmentTree tree(std::vector{1, 3, 2, 5, 4}); 12 | EXPECT_EQ(tree.getResult(1, 3), 2); 13 | EXPECT_EQ(tree.getResult(0, 5), 1); 14 | EXPECT_EQ(tree.getElement(0), 1); 15 | } 16 | 17 | TEST(BottomUpMinSegmentTree, FindFirstMinimum) { 18 | BottomUpMinSegmentTree tree(std::vector{3, 2, 3, 4, 2}); 19 | EXPECT_EQ(tree.getResult(0, 5), 2); 20 | EXPECT_EQ(tree.getFirstMinimum(), 1u); 21 | 22 | tree.set(1, 5); 23 | EXPECT_EQ(tree.getFirstMinimum(), 4u); 24 | 25 | tree.set(2, 1); 26 | EXPECT_EQ(tree.getFirstMinimum(), 2u); 27 | } 28 | -------------------------------------------------------------------------------- /tests/dataStructures/segmentTree/TopDownSumSegmentTree.cpp: -------------------------------------------------------------------------------- 1 | // Confidential Information. "AIM High Tech" LLC 2 | 3 | #include 4 | #include 5 | 6 | TEST(TopDownSumSegmentTree, CreationFromNumber) { 7 | TopDownSumSegmentTree tree(5); 8 | EXPECT_EQ(tree.getResult(3, 4), 0); 9 | } 10 | 11 | TEST(TopDownSumSegmentTree, CreationFromList) { 12 | TopDownSumSegmentTree tree(std::vector{1, 3, 2, 5, 4}); 13 | EXPECT_EQ(tree.getResult(1, 3), 5); 14 | EXPECT_EQ(tree.getResult(0, 5), 15); 15 | } 16 | 17 | TEST(TopDownSumSegmentTree, GetFirstPrefixAtLeast) { 18 | TopDownSumSegmentTree tree(std::vector{1, 3, 2, 5, 4}); 19 | tree.getFirstPrefixAtLeast(0); 20 | EXPECT_EQ(tree.getFirstPrefixAtLeast(0), 0u); 21 | EXPECT_EQ(tree.getFirstPrefixAtLeast(3), 2u); 22 | EXPECT_EQ(tree.getFirstPrefixAtLeast(25), 6u); 23 | EXPECT_EQ(tree.getFirstPrefixAtLeast(6), 3u); 24 | EXPECT_EQ(tree.getFirstPrefixAtLeast(5), 3u); 25 | } 26 | 27 | -------------------------------------------------------------------------------- /tests/detectionIdiom.hpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | struct nonesuch { 4 | nonesuch() = delete; 5 | ~nonesuch() = delete; 6 | nonesuch(nonesuch const&) = delete; 7 | void operator=(nonesuch const&) = delete; 8 | }; 9 | 10 | namespace detail { 11 | template class Op, class... Args> 12 | struct detector { 13 | using value_t = std::false_type; 14 | using type = Default; 15 | }; 16 | 17 | template class Op, class... Args> 18 | struct detector>, Op, Args...> { 19 | using value_t = std::true_type; 20 | using type = Op; 21 | }; 22 | 23 | } // namespace detail 24 | 25 | template class Op, class... Args> 26 | using is_detected = typename detail::detector::value_t; 27 | 28 | template class Op, class... Args> 29 | using detected_t = typename detail::detector::type; 30 | 31 | template class Op, class... Args> 32 | using detected_or = detail::detector; 33 | 34 | template< template class Op, class... Args > 35 | constexpr bool is_detected_v = is_detected::value; 36 | 37 | template< class Default, template class Op, class... Args > 38 | using detected_or_t = typename detected_or::type; 39 | 40 | template class Op, class... Args> 41 | using is_detected_exact = std::is_same>; 42 | 43 | template class Op, class... Args> 44 | constexpr bool is_detected_exact_v = is_detected_exact::value; 45 | 46 | template class Op, class... Args> 47 | using is_detected_convertible = std::is_convertible, To>; 48 | 49 | template class Op, class... Args> 50 | constexpr bool is_detected_convertible_v = is_detected_convertible::value; 51 | -------------------------------------------------------------------------------- /tests/geometry/Point2D.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | TEST(Point2D, TriangleAreaTest) { 5 | using P = Point2D; 6 | 7 | EXPECT_EQ(doubledArea(P(0, 0), P(0, 1), P(1, 0)), 1); 8 | EXPECT_EQ(doubledArea(P(0, 0), P(1, 0), P(0, 1)), 1); 9 | 10 | EXPECT_EQ(doubledArea(P(3, 5), P(-7, 8), P(-2, -1)), 75); 11 | } 12 | 13 | TEST(Point2D, TriangleAreaTestNoOverflow) { 14 | using P = Point2D; 15 | EXPECT_EQ(doubledArea(P(0, 0), P(0, 1'000'000'000), P(1'000'000, 0)), 1'000'000'000'000'000); 16 | } 17 | -------------------------------------------------------------------------------- /tests/geometry/convexHull.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | using Point = Point2D; 5 | 6 | TEST(ConvexHullTest, SamePointsInCounterClockwiseOrderForSquare) { 7 | std::vector points = { 8 | {0, 0}, 9 | {1, 1}, 10 | {0, 1}, 11 | {1, 0}, 12 | }; 13 | std::vector expected = { 14 | {0, 0}, 15 | {1, 0}, 16 | {1, 1}, 17 | {0, 1}, 18 | }; 19 | EXPECT_EQ(convexHull(points), expected); 20 | } 21 | 22 | TEST(ConvexHullTest, CentralPointDisappears) { 23 | std::vector points = { 24 | {0, 0}, 25 | {2, 2}, 26 | {1, 1}, 27 | {2, 0}, 28 | {0, 2}, 29 | }; 30 | std::vector expected = { 31 | {0, 0}, 32 | {2, 0}, 33 | {2, 2}, 34 | {0, 2}, 35 | }; 36 | EXPECT_EQ(convexHull(points), expected); 37 | } 38 | 39 | TEST(ConvexHullTest, PointOnTheEdgeDisappears) { 40 | std::vector points = { 41 | {0, 2}, 42 | {2, 0}, 43 | {0, 0}, 44 | {2, 2}, 45 | {1, 2}, 46 | }; 47 | std::vector expected = { 48 | {0, 0}, 49 | {2, 0}, 50 | {2, 2}, 51 | {0, 2}, 52 | }; 53 | EXPECT_EQ(convexHull(points), expected); 54 | } 55 | 56 | TEST(ConvexHullTest, ConvexHullOnIndices) { 57 | std::vector points = { 58 | {0, 0}, 59 | {2, 2}, 60 | {1, 2}, 61 | {0, 2}, 62 | {2, 0}, 63 | }; 64 | std::vector indices({0, 1, 2, 3, 4}); 65 | std::vector expectedIndices = {0, 4, 1, 3}; 66 | 67 | auto actual = convexHull(indices, [&](int i) { 68 | return points[i]; 69 | }); 70 | EXPECT_EQ(actual, expectedIndices); 71 | } 72 | -------------------------------------------------------------------------------- /tests/graphs/algorithms/dynamicConnectivityOffline.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | TEST(DynamicConnectivityOfflineTest, NoQueriesEmptyResult) { 6 | DynamicConnectivityTestBuilder test; 7 | ASSERT_EQ(dynamicConnectivity(std::move(test).build(), 5), std::vector{}); 8 | } 9 | 10 | TEST(DynamicConnectivityOfflineTest, NoQueriesWithChangingEdgesEmptyResult) { 11 | DynamicConnectivityTestBuilder test; 12 | test.addEdge(0, 1); 13 | test.addEdge(3, 2); 14 | test.addEdge(0, 1); 15 | test.removeEdge(3, 2); 16 | ASSERT_EQ(dynamicConnectivity(std::move(test).build(), 5), std::vector{}); 17 | } 18 | 19 | TEST(DynamicConnectivityOfflineTest, SameVertexIsConnected) { 20 | DynamicConnectivityTestBuilder test; 21 | test.addQuery(0, 0); 22 | ASSERT_EQ(dynamicConnectivity(std::move(test).build(), 2), std::vector{true}); 23 | } 24 | 25 | TEST(DynamicConnectivityOfflineTest, DifferentVertexAreDisconnectedInEmptyGraph) { 26 | DynamicConnectivityTestBuilder test; 27 | test.addQuery(0, 1); 28 | ASSERT_EQ(dynamicConnectivity(std::move(test).build(), 2), std::vector{false}); 29 | } 30 | 31 | TEST(DynamicConnectivityOfflineTest, AddingEdgeConnectsVertices) { 32 | DynamicConnectivityTestBuilder test; 33 | test.addQuery(0, 1); 34 | test.addEdge(0, 1); 35 | test.addQuery(0, 1); 36 | test.removeEdge(0, 1); 37 | test.addQuery(0, 1); 38 | ASSERT_EQ(dynamicConnectivity(std::move(test).build(), 2), (std::vector{false, true, false})); 39 | } 40 | 41 | TEST(DynamicConnectivityOfflineTest, ComponentsAreTransitive) { 42 | DynamicConnectivityTestBuilder test; 43 | test.addEdge(0, 1); 44 | test.addEdge(1, 2); 45 | test.addQuery(0, 2); 46 | ASSERT_EQ(dynamicConnectivity(std::move(test).build(), 3), (std::vector{true})); 47 | } 48 | 49 | TEST(DynamicConnectivityOfflineTest, UnrelatedEdgeDoNotConnect) { 50 | DynamicConnectivityTestBuilder test; 51 | test.addEdge(0, 1); 52 | test.addEdge(2, 3); 53 | test.addQuery(0, 2); 54 | ASSERT_EQ(dynamicConnectivity(std::move(test).build(), 4), (std::vector{false})); 55 | } 56 | 57 | TEST(DynamicConnectivityOfflineTest, MayRemoveEdgeWithWrongOrder) { 58 | DynamicConnectivityTestBuilder test; 59 | test.addQuery(0, 1); 60 | test.addEdge(0, 1); 61 | test.addQuery(0, 1); 62 | test.removeEdge(1, 0); 63 | test.addQuery(0, 1); 64 | ASSERT_EQ(dynamicConnectivity(std::move(test).build(), 2), (std::vector{false, true, false})); 65 | } 66 | 67 | TEST(DynamicConnectivityOfflineTest, CanAddSeveralPathAndRemoveBack) { 68 | DynamicConnectivityTestBuilder test; 69 | test.addEdge(0, 1); 70 | test.addEdge(1, 2); 71 | test.addQuery(0, 2); 72 | test.addEdge(0, 3); 73 | test.addEdge(3, 2); 74 | test.addQuery(0, 2); 75 | test.removeEdge(3, 2); 76 | test.addQuery(0, 2); 77 | test.removeEdge(0, 1); 78 | test.addQuery(0, 2); 79 | test.addEdge(1, 3); 80 | test.addQuery(0, 2); 81 | ASSERT_EQ(dynamicConnectivity(std::move(test).build(), 4), (std::vector{true, true, true, false, true})); 82 | } 83 | -------------------------------------------------------------------------------- /tests/graphs/algorithms/findIndependentSetInBipartiteGraph.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | bool independent( 9 | const std::vector>& graph, 10 | const std::pair, std::vector>& set) { 11 | for (auto l: set.first) { 12 | for (auto r: set.second) { 13 | if (std::find(graph[l].begin(), graph[l].end(), r) != graph[l].end()) { 14 | return false; 15 | } 16 | } 17 | } 18 | return true; 19 | } 20 | 21 | TEST(IndependentSet, EmptyGraph) { 22 | std::vector> g(5); 23 | auto result = findIndependentSetInBipartiteGraph(g, 3); 24 | EXPECT_EQ(result.first, indices(5)); 25 | EXPECT_EQ(result.second, indices(3)); 26 | } 27 | 28 | TEST(IndependentSet, SimpleEdge) { 29 | std::vector> g(5); 30 | g[2] = {1}; 31 | auto result = findIndependentSetInBipartiteGraph(g, 3); 32 | 33 | EXPECT_TRUE(independent(g, result)); 34 | EXPECT_EQ(result.first.size() + result.second.size(), static_cast(7)); 35 | } 36 | 37 | 38 | void testFullGraph(std::size_t leftSize, std::size_t rightSize) { 39 | auto rightHalf = indices(rightSize); 40 | std::vector> graph(leftSize, rightHalf); 41 | auto result = findIndependentSetInBipartiteGraph(graph, rightSize); 42 | EXPECT_TRUE(independent(graph, result)); 43 | EXPECT_EQ(result.first.size() + result.second.size(), std::max(leftSize, rightSize)); 44 | } 45 | 46 | TEST(IndependentSet, FullGraph) { 47 | testFullGraph(3, 3); 48 | testFullGraph(3, 5); 49 | testFullGraph(5, 4); 50 | } 51 | -------------------------------------------------------------------------------- /tests/identity.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | TEST(Identity, Integer) { 5 | ASSERT_EQ(identity(), 1); 6 | } 7 | -------------------------------------------------------------------------------- /tests/make_vector.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | TEST(MakeVector, MakeVector) { 5 | auto x = make_vector(3, 5, 10, 20); 6 | 7 | ASSERT_EQ(x.size(), static_cast(3)); 8 | ASSERT_EQ(x[1].size(), static_cast(5)); 9 | ASSERT_EQ(x[1][4].size(), static_cast(10)); 10 | ASSERT_EQ(x[1][4][2], 20); 11 | } 12 | -------------------------------------------------------------------------------- /tests/numbers/BigInteger.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | 8 | TEST(BigInteger, Equality) { 9 | EXPECT_EQ(BigInteger("0"), BigInteger("0")); 10 | EXPECT_NE(BigInteger("0"), BigInteger("1")); 11 | } 12 | 13 | TEST(BigInteger, Comparisons) { 14 | EXPECT_LT(BigInteger("0"), BigInteger("1")); 15 | EXPECT_LT(BigInteger("9"), BigInteger("10")); 16 | 17 | EXPECT_GT(BigInteger("321"), BigInteger("199")); 18 | 19 | EXPECT_GT(BigInteger( "1000000000000000000000"), BigInteger("100000000000000000000")); 20 | EXPECT_LT(BigInteger("-1000000000000000000000"), BigInteger("100000000000000000000")); 21 | } 22 | 23 | TEST(BigInteger, DefaultConstruction) { 24 | EXPECT_EQ(BigInteger("0"), BigInteger()); 25 | } 26 | 27 | TEST(BigInteger, Negatives) { 28 | EXPECT_EQ(BigInteger("-0"), BigInteger("0")); 29 | EXPECT_NE(BigInteger("-5"), BigInteger("5")); 30 | EXPECT_LT(BigInteger("-5"), BigInteger("0")); 31 | } 32 | 33 | TEST(BigInteger, LeadingZeros) { 34 | EXPECT_EQ(BigInteger("007"), BigInteger("7")); 35 | EXPECT_EQ(BigInteger("00"), BigInteger("0")); 36 | EXPECT_EQ(BigInteger("-0000"), BigInteger("0")); 37 | EXPECT_EQ(BigInteger("-0000005"), BigInteger("-5")); 38 | } 39 | 40 | std::string to_string(const BigInteger& rhs) { 41 | std::ostringstream ss; 42 | ss << rhs; 43 | return ss.str(); 44 | } 45 | 46 | TEST(BigInteger, CreatingFromStringLength9Works) { 47 | EXPECT_EQ(to_string(BigInteger("123456789")), "123456789"); 48 | } 49 | 50 | TEST(BigInteger, PreservesString) { 51 | std::mt19937 rnd; 52 | for (auto _ [[maybe_unused]]: range(100)) { 53 | std::string string; 54 | auto length = std::uniform_int_distribution(1, 1000)(rnd); 55 | for (auto index: range(length)) { 56 | string += std::uniform_int_distribution(index == 0 ? '1' : '0', '9')(rnd); 57 | } 58 | if (!string.empty()) { 59 | EXPECT_EQ(string, to_string(BigInteger(string))); 60 | } 61 | } 62 | } 63 | 64 | TEST(BigInteger, ConstructionFromInteger) { 65 | EXPECT_EQ(BigInteger("5"), BigInteger(5)); 66 | EXPECT_EQ(BigInteger("-17"), BigInteger(-17)); 67 | 68 | EXPECT_EQ(BigInteger(2u), BigInteger(2)); 69 | EXPECT_EQ(BigInteger(123456789987654321LL), BigInteger("123456789987654321")); 70 | } 71 | 72 | TEST(BigInteger, ConstructionFromCornerCases) { 73 | EXPECT_EQ(BigInteger("-2147483648"), BigInteger(std::numeric_limits::min())); 74 | EXPECT_EQ(BigInteger("2147483647"), BigInteger(std::numeric_limits::max())); 75 | EXPECT_EQ(BigInteger("-9223372036854775808"), BigInteger(std::numeric_limits::min())); 76 | EXPECT_EQ(BigInteger("9223372036854775807"), BigInteger(std::numeric_limits::max())); 77 | } 78 | 79 | TEST(BigInteger, Addition) { 80 | EXPECT_EQ(BigInteger(2) + BigInteger(3), BigInteger(5)); 81 | EXPECT_EQ(BigInteger(5) + BigInteger(-5), BigInteger()); 82 | EXPECT_EQ(BigInteger("-123482748923748923748923748932748923748923") + BigInteger("123482748923748923748923748932748923748923"), BigInteger()); 83 | EXPECT_EQ(BigInteger("999999999999999") + BigInteger(1), BigInteger("1000000000000000")); 84 | EXPECT_EQ(BigInteger(1) + BigInteger("999999999999999"), BigInteger("1000000000000000")); 85 | } 86 | 87 | TEST(BigInteger, Multiplication) { 88 | EXPECT_EQ(BigInteger("2") * 3, BigInteger("6")); 89 | EXPECT_EQ(BigInteger("2") * BigInteger("3"), BigInteger("6")); 90 | EXPECT_EQ(2LL * BigInteger("3"), BigInteger("6")); 91 | EXPECT_EQ(BigInteger(100000) * BigInteger(100000), BigInteger(10'000'000'000LL)); 92 | 93 | EXPECT_EQ( 94 | BigInteger("4785974389573489572489758937589347589347589347589347589347589432758934") * BigInteger("458094758943758923748923647236478326478236748236784236784643785634786578246597243"), 95 | BigInteger("2192429784302671467919007921697750410148554848247894746582207779373105073375035215686871375677131908065225960777754019816604326597006535602139008018962") 96 | ); 97 | 98 | EXPECT_EQ( 99 | BigInteger("72859743895789243758952387534789543789573489578934745894") * 57, 100 | BigInteger("4153005402059986894260286089483003996005688905999280515958") 101 | ); 102 | } 103 | -------------------------------------------------------------------------------- /tests/numbers/Zn.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | using Z = ZnConst<5>; 5 | TEST(Zn, Construction) { 6 | for (int i = 0; i <= 4; ++i) { 7 | EXPECT_EQ(Z::valueOf(i).intValue(), i); 8 | } 9 | EXPECT_EQ(Z::valueOf(128).intValue(), 3); 10 | EXPECT_EQ(Z::valueOf(-1).intValue(), 4); 11 | 12 | EXPECT_EQ(Z::valueOf(5LL).intValue(), 0); 13 | } 14 | 15 | TEST(Zn, DefaultConstruction) { 16 | EXPECT_EQ(Z().intValue(), 0); 17 | } 18 | 19 | TEST(Zn, SimpleOperations) { 20 | EXPECT_EQ(Z::valueOf(1) + Z::valueOf(2), Z::valueOf(3)); 21 | EXPECT_EQ(Z::valueOf(2) * Z::valueOf(3), Z::valueOf(1)); 22 | EXPECT_EQ(Z() * Z::valueOf(2), Z::valueOf(0)); 23 | } 24 | 25 | TEST(Zn, EqualityWithIntegers) { 26 | EXPECT_EQ(Z::valueOf(2), 2); 27 | EXPECT_EQ(Z::valueOf(7), 2); 28 | EXPECT_EQ(Z::valueOf(2), 7); 29 | EXPECT_EQ(Z::valueOf(2), 7LL); 30 | EXPECT_EQ(Z::valueOf(2), static_cast(7)); 31 | EXPECT_EQ(Z::valueOf(2), 7U); 32 | 33 | EXPECT_NE(Z::valueOf(2), 1); 34 | EXPECT_NE(Z(), 42); 35 | } 36 | 37 | TEST(Zn, OperationsWithInteger) { 38 | EXPECT_EQ(Z::valueOf(2) + 3, 0); 39 | EXPECT_EQ(1 + Z::valueOf(2), 3); 40 | EXPECT_EQ(4 * Z::valueOf(3), -3); 41 | EXPECT_EQ(Z::valueOf(3) * 3, 9); 42 | EXPECT_EQ(1 / Z::valueOf(3), 2); 43 | EXPECT_EQ(Z::valueOf(2) / 4, 3); 44 | } 45 | 46 | TEST(Zn, DivisionIsInverseOfMultiplication) { 47 | for (int a = 0; a < 5; ++a) { 48 | for (int b = 1; b < 5; ++b) { 49 | EXPECT_EQ(Z::valueOf(a) / Z::valueOf(b) * Z::valueOf(b), a); 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /tests/numbers/bits.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | TEST(IsPowerOf2Test, DetectPowersOf2) { 5 | EXPECT_TRUE(isPowerOf2(1)); 6 | EXPECT_TRUE(isPowerOf2(32)); 7 | EXPECT_TRUE(isPowerOf2(1 << 30)); 8 | EXPECT_TRUE(isPowerOf2(4)); 9 | } 10 | 11 | TEST(IsPowerOf2Test, DoesntDetectNotPowers) { 12 | EXPECT_FALSE(isPowerOf2(3)); 13 | EXPECT_FALSE(isPowerOf2(0)); 14 | EXPECT_FALSE(isPowerOf2(42)); 15 | EXPECT_FALSE(isPowerOf2((1 << 15) - 1)); 16 | } 17 | 18 | TEST(LeastSignificantBitTest, LeastSignificantBit) { 19 | EXPECT_EQ(leastSignificantBit(15), static_cast(0)); 20 | EXPECT_EQ(leastSignificantBit(1 << 30), static_cast(30)); 21 | EXPECT_EQ(leastSignificantBit(36), static_cast(2)); 22 | } 23 | -------------------------------------------------------------------------------- /tests/numbers/division.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | TEST(DivideCeilTest, PositiveWholeDivision) { 5 | EXPECT_EQ(divideCeil(6, 2), 3); 6 | EXPECT_EQ(divideCeil(48, 12), 4); 7 | } 8 | 9 | TEST(DivideCeilTest, PositiveNotWholeDivision) { 10 | EXPECT_EQ(divideCeil(17, 2), 9); 11 | EXPECT_EQ(divideCeil(101, 5), 21); 12 | EXPECT_EQ(divideCeil(1, 101), 1); 13 | } 14 | 15 | TEST(DivideCeilTest, NegativeWholeDivions) { 16 | EXPECT_EQ(divideCeil(-70, -5), 14); 17 | EXPECT_EQ(divideCeil(12, -4), -3); 18 | EXPECT_EQ(divideCeil(-8, 2), -4); 19 | } 20 | 21 | TEST(DivideCeilTest, NegativesNotWholeDivision) { 22 | EXPECT_EQ(divideCeil(-33, 5), -6); 23 | EXPECT_EQ(divideCeil(23, -3), -7); 24 | EXPECT_EQ(divideCeil(-15, -2), 8); 25 | EXPECT_EQ(divideCeil(-1, 5), 0); 26 | } 27 | 28 | TEST(DivideFloorTest, PositiveWholeDivision) { 29 | EXPECT_EQ(divideFloor(6, 2), 3); 30 | EXPECT_EQ(divideFloor(48, 12), 4); 31 | } 32 | 33 | TEST(DivideFloorTest, PositiveNotWholeDivision) { 34 | EXPECT_EQ(divideFloor(17, 2), 8); 35 | EXPECT_EQ(divideFloor(101, 5), 20); 36 | EXPECT_EQ(divideFloor(1, 101), 0); 37 | } 38 | 39 | TEST(DivideFloorTest, NegativeWholeDivions) { 40 | EXPECT_EQ(divideFloor(-70, -5), 14); 41 | EXPECT_EQ(divideFloor(12, -4), -3); 42 | EXPECT_EQ(divideFloor(-8, 2), -4); 43 | } 44 | 45 | TEST(DivideFloorTest, NegativesNotWholeDivision) { 46 | EXPECT_EQ(divideFloor(-33, 5), -7); 47 | EXPECT_EQ(divideFloor(23, -3), -8); 48 | EXPECT_EQ(divideFloor(-15, -2), 7); 49 | EXPECT_EQ(divideFloor(-1, 5), -1); 50 | } 51 | 52 | TEST(DivideTowardsZeroTest, PositiveWholeDivision) { 53 | EXPECT_EQ(divideTowardsZero(6, 2), 3); 54 | EXPECT_EQ(divideTowardsZero(48, 12), 4); 55 | } 56 | 57 | TEST(DivideTowardsZeroTest, PositiveNotWholeDivision) { 58 | EXPECT_EQ(divideTowardsZero(17, 2), 8); 59 | EXPECT_EQ(divideTowardsZero(101, 5), 20); 60 | EXPECT_EQ(divideTowardsZero(1, 101), 0); 61 | } 62 | 63 | TEST(DivideTowardsZeroTest, NegativeWholeDivions) { 64 | EXPECT_EQ(divideTowardsZero(-70, -5), 14); 65 | EXPECT_EQ(divideTowardsZero(12, -4), -3); 66 | EXPECT_EQ(divideTowardsZero(-8, 2), -4); 67 | } 68 | 69 | TEST(DivideTowardsZeroTest, NegativesNotWholeDivision) { 70 | EXPECT_EQ(divideTowardsZero(-33, 5), -6); 71 | EXPECT_EQ(divideTowardsZero(23, -3), -7); 72 | EXPECT_EQ(divideTowardsZero(-15, -2), 7); 73 | EXPECT_EQ(divideTowardsZero(-1, 5), 0); 74 | } 75 | 76 | TEST(DivideAwayFromZeroTest, PositiveWholeDivision) { 77 | EXPECT_EQ(divideAwayFromZero(6, 2), 3); 78 | EXPECT_EQ(divideAwayFromZero(48, 12), 4); 79 | } 80 | 81 | TEST(DivideAwayFromZeroTest, PositiveNotWholeDivision) { 82 | EXPECT_EQ(divideAwayFromZero(17, 2), 9); 83 | EXPECT_EQ(divideAwayFromZero(101, 5), 21); 84 | EXPECT_EQ(divideAwayFromZero(1, 101), 1); 85 | } 86 | 87 | TEST(DivideAwayFromZeroTest, NegativeWholeDivions) { 88 | EXPECT_EQ(divideAwayFromZero(-70, -5), 14); 89 | EXPECT_EQ(divideAwayFromZero(12, -4), -3); 90 | EXPECT_EQ(divideAwayFromZero(-8, 2), -4); 91 | } 92 | 93 | TEST(DivideAwayFromZeroTest, NegativesNotWholeDivision) { 94 | EXPECT_EQ(divideAwayFromZero(-33, 5), -7); 95 | EXPECT_EQ(divideAwayFromZero(23, -3), -8); 96 | EXPECT_EQ(divideAwayFromZero(-15, -2), 8); 97 | EXPECT_EQ(divideAwayFromZero(-1, 5), -1); 98 | } 99 | -------------------------------------------------------------------------------- /tests/numbers/divisors.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | TEST(DivisorsTest, DivisorsTest) { 5 | EXPECT_EQ(sortedDivisors(24), (std::vector{1, 2, 3, 4, 6, 8, 12, 24})); 6 | } 7 | 8 | TEST(DivisorsTest, HandlesPower) { 9 | EXPECT_EQ(sortedDivisors(27), (std::vector{1, 3, 9, 27})); 10 | } 11 | 12 | TEST(DivisorsTest, HandlesOnes) { 13 | EXPECT_EQ(sortedDivisors(1), (std::vector{1})); 14 | } 15 | -------------------------------------------------------------------------------- /tests/numbers/extended_gcd.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | TEST(ExtendedGcdTest, HandlesCoPrimes) { 5 | int x, y; 6 | EXPECT_EQ(extendedGcd(3, 5, x, y), 1); 7 | EXPECT_EQ(x * 3 + y * 5, 1); 8 | 9 | EXPECT_EQ(extendedGcd(8, 9, x, y), 1); 10 | EXPECT_EQ(x * 8 + y * 9, 1); 11 | } 12 | 13 | TEST(ExtendedGcdTest, HandlesDivisible) { 14 | int x, y; 15 | EXPECT_EQ(extendedGcd(2, 8, x, y), 2); 16 | EXPECT_EQ(x * 2 + y * 8, 2); 17 | 18 | EXPECT_EQ(extendedGcd(9, 3, x, y), 3); 19 | EXPECT_EQ(x * 9 + y * 3, 3); 20 | } 21 | 22 | TEST(ExtendedGcdTest, HandlesZero) { 23 | int x, y; 24 | EXPECT_EQ(extendedGcd(0, 5, x, y), 5); 25 | EXPECT_EQ(y, 1); 26 | 27 | EXPECT_EQ(extendedGcd(7, 0, x, y), 7); 28 | EXPECT_EQ(x, 1); 29 | } 30 | 31 | TEST(ExtendedGcdTest, HandlesNOnTrivialGcd) { 32 | int x, y; 33 | EXPECT_EQ(extendedGcd(15, 40, x, y), 5); 34 | EXPECT_EQ(x * 15 + y * 40, 5); 35 | } 36 | 37 | TEST(ExtendedGcdTest, HandlesNegatives) { 38 | int x, y; 39 | int g = extendedGcd(-2, 5, x, y); 40 | EXPECT_EQ(abs(g), 1); 41 | EXPECT_EQ(x * (-2) + y * 5, g); 42 | } 43 | -------------------------------------------------------------------------------- /tests/numbers/gcd.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | TEST(GcdTest, HandlesPositiveNumbers) { 5 | EXPECT_EQ(gcd(5, 7), 1); 6 | EXPECT_EQ(gcd(20, 20), 20); 7 | EXPECT_EQ(gcd(4, 6), 2); 8 | EXPECT_EQ(gcd(1, 19), 1); 9 | EXPECT_EQ(gcd(3, 21), 3); 10 | EXPECT_EQ(gcd(14, 2), 2); 11 | } 12 | 13 | TEST(GcdTest, GcdOfZeroIsOtherNumber) { 14 | EXPECT_EQ(gcd(0, 0), 0); 15 | EXPECT_EQ(gcd(0, 3), 3); 16 | EXPECT_EQ(gcd(60, 0), 60); 17 | } 18 | 19 | TEST(GcdTest, HandlesNegatives) { 20 | EXPECT_EQ(abs(gcd(-2, 6)), 2); 21 | EXPECT_EQ(abs(gcd(-15, -40)), 5); 22 | EXPECT_EQ(abs(gcd(5, -7)), 1); 23 | } 24 | -------------------------------------------------------------------------------- /tests/numbers/lcm.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | TEST(LcmTest, CalculatesLcm) { 5 | EXPECT_EQ(lcm(3, 5), 15); 6 | EXPECT_EQ(lcm(2, 8), 8); 7 | EXPECT_EQ(lcm(6, 8), 24); 8 | EXPECT_EQ(lcm(10, 1), 10); 9 | } 10 | -------------------------------------------------------------------------------- /tests/numbers/numbers.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | TEST(NumbersTest, FactorialTest) { 6 | EXPECT_EQ(factorial(0), 1); 7 | EXPECT_EQ(factorial(1), 1); 8 | EXPECT_EQ(factorial(2), 2); 9 | EXPECT_EQ(factorial(5), 120); 10 | 11 | using Z = ZnConst<97>; 12 | EXPECT_EQ(factorial(100), Z()); 13 | } 14 | 15 | TEST(NumberTest, FactorialsTest) { 16 | EXPECT_EQ(factorials(0), std::vector{1}); 17 | EXPECT_EQ(factorials(5), (std::vector{1, 1, 2, 6, 24, 120})); 18 | } 19 | 20 | TEST(NumbersTest, BinomialTest) { 21 | EXPECT_EQ(binomial(0, 0), 1); 22 | EXPECT_EQ(binomial(5, 3), 10); 23 | EXPECT_EQ(binomial(10, 10), 1); 24 | } 25 | 26 | TEST(NumbersTest, PascalTriangleRowTest) { 27 | using Result = std::vector; 28 | EXPECT_EQ(pascalTriangleRow(0), Result{1}); 29 | EXPECT_EQ(pascalTriangleRow(1), (Result{1, 1})); 30 | EXPECT_EQ(pascalTriangleRow(5), (Result{1, 5, 10, 10, 5, 1})); 31 | 32 | EXPECT_EQ(pascalTriangleRow(2, 5), (Result{1, 2, 1, 0, 0, 0})); 33 | EXPECT_EQ(pascalTriangleRow(10, 2), (Result{1, 10, 45})); 34 | } 35 | 36 | TEST(NumbersTest, BinomialsTest) { 37 | auto result = binomials(5); 38 | ASSERT_EQ(result.size(), static_cast(6)); 39 | for (int i = 0; i <= 5; ++i) { 40 | ASSERT_EQ(result[i].size(), static_cast(6)) << "i: " << i; 41 | for (int j = 0; j <= i; ++j) { 42 | EXPECT_EQ(result[i][j], binomial(i, j)) << "i: " << i << " j:" << j; 43 | } 44 | } 45 | } 46 | 47 | TEST(NumbersTest, StarsAndBars) { 48 | EXPECT_EQ(starsAndBars(0, 0), 1); 49 | EXPECT_EQ(starsAndBars(5, 1), 1); 50 | EXPECT_EQ(starsAndBars(5, 2), 6); 51 | EXPECT_EQ(starsAndBars(1, 12), 12); 52 | } 53 | -------------------------------------------------------------------------------- /tests/numbers/primes.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | namespace { 6 | const std::vector smallPrimes = {2, 3, 5, 7}; 7 | } 8 | 9 | TEST(PrimesTest, PrimeMapOnRange) { 10 | EXPECT_EQ(primeMapOnRange(11, 14, smallPrimes), (std::vector{true, false, true})); 11 | { 12 | auto allMap = primeMap(19); 13 | EXPECT_EQ(primeMapOnRange(10, 20, smallPrimes), (std::vector{allMap.begin() + 10, allMap.end()})); 14 | } 15 | } 16 | 17 | TEST(PrimesTest, PrimesOnRange) { 18 | EXPECT_EQ(primesOnRange(11, 14, smallPrimes), (std::vector{11, 13})); 19 | EXPECT_EQ(primesOnRange(1, 10, smallPrimes), smallPrimes); 20 | } 21 | 22 | TEST(PrimesTest, PrimesOnRangeDoesntIncludeLast) { 23 | EXPECT_EQ(primesOnRange(11, 13, smallPrimes), (std::vector{11})); 24 | } 25 | 26 | TEST(PrimesTest, PrimeMapOnRangeWorksForBig) { 27 | int64_t begin = 1'000'000'000'000; 28 | int64_t end = 1'000'000'001'000; 29 | auto map = primeMapOnRange(begin, end, allPrimes(1'100'000)); 30 | for (auto x: range(begin, end)) { 31 | EXPECT_EQ(map[x - begin], isPrime(x)) << "x: " << x; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /tests/operator_size.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | inline std::size_t operator ""_size (unsigned long long value) { 6 | return static_cast(value); 7 | } 8 | -------------------------------------------------------------------------------- /tests/parallel.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | template 7 | std::ptrdiff_t rangeSize(IntegerRange range) { 8 | return std::distance(range.begin(), range.end()); 9 | } 10 | 11 | TEST(WorkerRange, EqualParts) { 12 | for (int i = 0; i < 5; ++i) { 13 | ASSERT_EQ(rangeSize(workerRange(10, i, 5)), 2); 14 | } 15 | } 16 | 17 | TEST(WorkerRange, UnequalParts) { 18 | int size = 27; 19 | int nodes = 5; 20 | for (int i = 0; i < nodes; ++i) { 21 | auto workerRangeSize = rangeSize(workerRange(size, i, nodes)); 22 | ASSERT_GE(workerRangeSize, divideFloor(size, nodes)) << "node: " << i; 23 | ASSERT_LE(workerRangeSize, divideCeil(size, nodes)) << "node: " << i; 24 | } 25 | } 26 | 27 | TEST(WorkerRange, EverythingOne) { 28 | std::map usedCount; 29 | int size = 27; 30 | int nodes = 5; 31 | for (int node = 0; node < nodes; ++node) { 32 | for (int x: workerRange(size, node, nodes)) { 33 | ++usedCount[x]; 34 | } 35 | } 36 | ASSERT_EQ(usedCount.size(), static_cast(size)); 37 | for (int i = 0; i < size; ++i) { 38 | ASSERT_EQ(usedCount[i], 1) << "i: " << i; 39 | } 40 | } 41 | 42 | TEST(WorkerRange, OneNode) { 43 | ASSERT_EQ(*workerRange(5, 0, 1).begin(), 0); 44 | ASSERT_EQ(*workerRange(5, 0, 1).end(), 5); 45 | } 46 | 47 | TEST(WorkerRange, EmptyRange) { 48 | ASSERT_EQ(workerRange(0, 7, 10).begin(), workerRange(0, 7, 10).end()); 49 | } 50 | -------------------------------------------------------------------------------- /tests/ranges/indices.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | TEST(IndicesTest, ReturnFirstIndices) { 5 | EXPECT_EQ(indices(3), (std::vector{0, 1, 2})); 6 | } 7 | 8 | TEST(IndicesTest, WorksWithEmptyRange) { 9 | EXPECT_EQ(indices(0), std::vector()); 10 | } 11 | 12 | TEST(IndicesTest, DetectsTypes) { 13 | int64_t x = 5; 14 | static_assert(std::is_same>::value); 15 | static_assert(std::is_same>::value); 16 | } 17 | -------------------------------------------------------------------------------- /tests/ranges/pairwiseMerge.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | TEST(PairwiseMerge, Unique) { 7 | std::vector v = {3, 5, 7, 7, 5, 5, 5, 5}; 8 | pairwiseMerge(v, std::equal_to<>()); 9 | EXPECT_EQ(v, (std::vector{3, 5, 7, 5})); 10 | } 11 | 12 | TEST(PairwiseMerge, Empty) { 13 | std::vector v; 14 | pairwiseMerge(v, std::equal_to<>()); 15 | EXPECT_TRUE(v.empty()); 16 | } 17 | 18 | TEST(PairwiseMerge, OneElement) { 19 | std::vector v = {42}; 20 | auto v_original = v; 21 | pairwiseMerge(v, std::equal_to<>()); 22 | EXPECT_EQ(v, v_original); 23 | } 24 | 25 | TEST(PairwiseMerge, CalcualteSum) { 26 | std::vector v = {3, 2, 5, 42}; 27 | pairwiseMerge(v, [](int& l, int r) { 28 | l += r; 29 | return true; 30 | }); 31 | EXPECT_EQ(v, std::vector{52}); 32 | } 33 | 34 | TEST(PairwiseMerge, MergeSegments) { 35 | using Segment = std::pair; 36 | std::vector v = {{0, 1}, {1, 5}, {7, 10}, {10, 12}, {12, 15}, {20, 21}}; 37 | auto merge_segments = [&](Segment& l, const Segment& r) { 38 | if (l.second == r.first) { 39 | l.second = r.second; 40 | return true; 41 | } 42 | return false; 43 | }; 44 | 45 | pairwiseMerge(v, merge_segments); 46 | EXPECT_EQ(v, (std::vector{{0, 5}, {7, 15}, {20, 21}})); 47 | } 48 | -------------------------------------------------------------------------------- /tests/ranges/prefixSums.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | TEST(PrefixSumsTest, SumsVector) { 8 | std::vector v = {4, 2, 7}; 9 | EXPECT_EQ(prefixSums(v), (std::vector{0, 4, 6, 13})); 10 | } 11 | 12 | TEST(PrefixSumsTest, SumsSet) { 13 | std::set x = {1, 10, 100}; 14 | EXPECT_EQ(prefixSums(x), (std::vector{0, 1, 11, 111})); 15 | } 16 | 17 | TEST(PrefixSumsTest, SumsEmptyRange) { 18 | EXPECT_EQ(prefixSums(std::vector{}), (std::vector{0})); 19 | } 20 | 21 | TEST(PrefixSumsTest, SumsIntegerRange) { 22 | std::size_t len = 10; 23 | auto res = prefixSums(inclusiveRange(static_cast(1), len)); 24 | ASSERT_EQ(res.size(), len + 1); 25 | for (std::size_t i = 0; i <= len; ++i) { 26 | res[i] = i * (i + 1) / 2; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /tests/ranges/wrappers.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | TEST(WrappersTest, Reversed) { 7 | EXPECT_EQ(reversed(std::vector{5, 7, 2, 3}), (std::vector{3, 2, 7, 5})); 8 | } 9 | 10 | TEST(WrappersTest, Sorted) { 11 | EXPECT_EQ(sorted(std::vector{5, 7, 2, 3}), (std::vector{2, 3, 5, 7})); 12 | } 13 | 14 | TEST(WrapperTest, SortedWithComparator) { 15 | EXPECT_EQ(sorted(std::vector{5, 7, 2, 3}, std::greater()), (std::vector{7, 5, 3, 2})); 16 | } 17 | 18 | TEST(WrapperTest, Unique) { 19 | std::vector v = {5, 7, 7, 7, 3}; 20 | unique(v); 21 | EXPECT_EQ(v, (std::vector{5, 7, 3})); 22 | } 23 | 24 | TEST(WrapperTest, UniquePreservesNotAdjascentElements) { 25 | std::vector v = {1, 2, 1}; 26 | std::vector original_v = v; 27 | unique(v); 28 | EXPECT_EQ(v, original_v); 29 | } 30 | 31 | TEST(WrapperTest, FindsMaxElement) { 32 | std::vector v = {5, 7, 3}; 33 | EXPECT_EQ(*max_element(v), 7); 34 | } 35 | 36 | TEST(WrapperTest, MaxOfEmptyRangeIsBegin) { 37 | std::vector v; 38 | EXPECT_EQ(max_element(v), v.begin()); 39 | } 40 | 41 | TEST(WrapperTest, FindsMinElement) { 42 | std::vector v = {5, 7, 3}; 43 | EXPECT_EQ(*min_element(v), 3); 44 | } 45 | 46 | TEST(WrapperTest, MinOfEmptyRangeIsBegin) { 47 | std::vector v; 48 | EXPECT_EQ(min_element(v), v.begin()); 49 | } 50 | 51 | TEST(WrapperTest, FindsMaxOfPartOfRange) { 52 | std::vector v = {100, 1, 2, 5, 0, 15, -1}; 53 | EXPECT_EQ(*max_element(make_range(v.begin() + 1, v.begin() + 4)), 5); 54 | } 55 | 56 | TEST(WrappersTest, FindsNextPermutation) { 57 | std::vector v = {1, 3, 2}; 58 | EXPECT_TRUE(next_permutation(v)); 59 | EXPECT_EQ(v, (std::vector{2, 1, 3})); 60 | } 61 | 62 | TEST(WrappersTest, NextPermuationCyclesAfterLastPermutation) { 63 | std::vector v = {3, 2, 1}; 64 | EXPECT_FALSE(next_permutation(v)); 65 | EXPECT_EQ(v, (std::vector{1, 2, 3})); 66 | } 67 | -------------------------------------------------------------------------------- /tests/strings/StringHash.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | template 7 | struct StringHashTest : ::testing::Test {}; 8 | 9 | using Hashers = ::testing::Types; 10 | TYPED_TEST_CASE(StringHashTest, Hashers); 11 | 12 | TYPED_TEST(StringHashTest, HasEqualHashForEqualStrings) { 13 | StringHash hash("abacaba"); 14 | EXPECT_EQ(hash.hash(0, 2), hash.hash(4, 6)); 15 | EXPECT_EQ(hash.hash(2, 3), hash.hash(4, 5)); 16 | } 17 | 18 | TYPED_TEST(StringHashTest, PrefixSuffixHash) { 19 | StringHash hash("abacaba"); 20 | EXPECT_EQ(hash.prefixHash(5), hash.hash(0, 5)); 21 | EXPECT_EQ(hash.prefixHash(3), hash.suffixHash(4)); 22 | EXPECT_EQ(hash.suffixHash(6), hash.hash(6, 7)); 23 | } 24 | 25 | TYPED_TEST(StringHashTest, SmallDifferentStringHaveDifferentHash) { 26 | StringHash hash("abacaba"); 27 | EXPECT_NE(hash.hash(1, 3), hash.hash()); 28 | EXPECT_NE(hash.hash(0, 1), hash.hash(3, 4)); 29 | EXPECT_NE(hash.prefixHash(1), hash.prefixHash(2)); 30 | } 31 | 32 | TYPED_TEST(StringHashTest, HashForEmptySubstringsAreEqual) { 33 | StringHash hash("abacaba"); 34 | EXPECT_EQ(hash.hash(3, 3), hash.hash(5, 5)); 35 | } 36 | 37 | TYPED_TEST(StringHashTest, HashesInDifferentStringAreSame) { 38 | StringHash abacaba("abacaba"); 39 | StringHash abra("abrackadabra"); 40 | 41 | EXPECT_EQ(abacaba.hash(0, 2), abra.hash(0, 2)); 42 | EXPECT_EQ(abacaba.hash(2, 4), abra.hash(3, 5)); 43 | EXPECT_EQ(abacaba.hash(1, 2), abra.hash(9, 10)); 44 | } 45 | -------------------------------------------------------------------------------- /tests/strings/SuffixArray.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | TEST(SuffixArray, NthSuffix) { 9 | SuffixArray suffixArray("abacaba"); 10 | ASSERT_EQ(suffixArray.getNthSuffix(0), static_cast(6)); 11 | ASSERT_EQ(suffixArray.getNthSuffix(4), static_cast(5)); 12 | ASSERT_EQ(suffixArray.getNthSuffix(6), static_cast(3)); 13 | 14 | ASSERT_EQ(suffixArray.getPosition(0), static_cast(2)); 15 | ASSERT_EQ(suffixArray.getPosition(1), static_cast(5)); 16 | ASSERT_EQ(suffixArray.getPosition(2), static_cast(3)); 17 | ASSERT_EQ(suffixArray.getPosition(4), static_cast(1)); 18 | } 19 | 20 | TEST(SuffixArray, EmptyNoFail) { 21 | SuffixArray suffixArray(""); 22 | } 23 | 24 | TEST(SuffixArray, Single) { 25 | SuffixArray suffixArray("x"); 26 | ASSERT_EQ(suffixArray.getNthSuffix(0), static_cast(0)); 27 | ASSERT_EQ(suffixArray.getPosition(0), static_cast(0)); 28 | } 29 | 30 | TEST(SuffixArray, Big) { 31 | std::mt19937 gen; 32 | std::size_t n = 100; 33 | std::string string(n, ' '); 34 | std::uniform_int_distribution dist('A', 'Z'); 35 | 36 | for (std::size_t i = 0; i < n; ++i) { 37 | string[i] = dist(gen); 38 | } 39 | 40 | SuffixArray suffixArray(string); 41 | std::vector indicies(n); 42 | for (std::size_t i = 0; i < n; ++i) { 43 | indicies[i] = i; 44 | } 45 | 46 | std::sort(indicies.begin(), indicies.end(), [&](std::size_t l, std::size_t r) { 47 | return string.substr(l) < string.substr(r); 48 | }); 49 | 50 | for (std::size_t i = 0; i < n; ++i) { 51 | ASSERT_EQ(suffixArray.getNthSuffix(i), indicies[i]) << "i: " << i; 52 | ASSERT_EQ(suffixArray.getPosition(indicies[i]), i) << "i: " << i; 53 | } 54 | } 55 | 56 | -------------------------------------------------------------------------------- /tests/strings/prefixFunction.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | TEST(PrefixFunctionTest, SimpleTest) { 6 | EXPECT_EQ(prefixFunction("abacaba"), (std::vector{0, 0, 1, 0, 1, 2, 3})); 7 | EXPECT_EQ(prefixFunction("abc"), (std::vector{0, 0, 0})); 8 | } 9 | 10 | TEST(PrefixFunctionTest, SameLettersTest) { 11 | size_t n = 123; 12 | std::vector expected(123); 13 | std::iota(expected.begin(), expected.end(), 0); 14 | EXPECT_EQ(prefixFunction(std::string(n, 'x')), expected); 15 | } 16 | 17 | TEST(PrefixFunctionTest, SimpleSubstringTest) { 18 | EXPECT_TRUE(isSubstring("abacaba", "a")); 19 | EXPECT_FALSE(isSubstring("abacaba", "d")); 20 | EXPECT_TRUE(isSubstring("abacaba", "abac")); 21 | EXPECT_FALSE(isSubstring("abacaba", "abc")); 22 | } 23 | 24 | TEST(PrefixFunctionTest, SubstringInDifferentParts) { 25 | EXPECT_TRUE(isSubstring("abdfe", "ab")); 26 | EXPECT_TRUE(isSubstring("abfde", "de")); 27 | EXPECT_TRUE(isSubstring("abfde", "bfd")); 28 | } 29 | 30 | TEST(PrefixFunctionTest, SubstringDoesnFailAfterPartialMatch) { 31 | EXPECT_TRUE(isSubstring("ababac", "abac")); 32 | } 33 | -------------------------------------------------------------------------------- /tests/typeTraits/IsContainer.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | static_assert(!IsContainer::value, ""); 6 | static_assert(IsContainer>::value, ""); 7 | static_assert(IsContainer::value, ""); 8 | -------------------------------------------------------------------------------- /tests/typeTraits/IsSaneInteger.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | static_assert(IsSaneInteger::value); 6 | static_assert(IsSaneInteger::value); 7 | static_assert(IsSaneInteger::value); 8 | 9 | static_assert(!IsSaneInteger::value); 10 | static_assert(!IsSaneInteger::value); 11 | static_assert(!IsSaneInteger::value); 12 | static_assert(!IsSaneInteger>::value); 13 | -------------------------------------------------------------------------------- /tests/updateMin.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | TEST(UpdateMinTest, UpdatesWhenSmaller) { 5 | int a = 5; 6 | updateMin(a, 3); 7 | EXPECT_EQ(a, 3); 8 | } 9 | 10 | TEST(UpdateMinTest, LeavesWhenGreater) { 11 | int a = 7; 12 | updateMin(a, 10); 13 | EXPECT_EQ(a, 7); 14 | } 15 | 16 | TEST(UpdateMaxTest, UpdatesWhenGreater) { 17 | int a = 7; 18 | updateMax(a, 10); 19 | EXPECT_EQ(a, 10); 20 | } 21 | 22 | TEST(UpdateMaxTest, LeavesOldWhenSmaller) { 23 | int a = 5; 24 | updateMax(a, 3); 25 | EXPECT_EQ(a, 5); 26 | } 27 | --------------------------------------------------------------------------------