|
| 1 | +--- |
| 2 | +data: |
| 3 | + _extendedDependsOn: |
| 4 | + - icon: ':heavy_check_mark:' |
| 5 | + path: weilycoder/poly/karatsuba.hpp |
| 6 | + title: Multiply two polynomials using the Karatsuba algorithm. |
| 7 | + _extendedRequiredBy: [] |
| 8 | + _extendedVerifiedWith: [] |
| 9 | + _isVerificationFailed: false |
| 10 | + _pathExtension: cpp |
| 11 | + _verificationStatusIcon: ':heavy_check_mark:' |
| 12 | + attributes: |
| 13 | + '*NOT_SPECIAL_COMMENTS*': '' |
| 14 | + PROBLEM: https://judge.yosupo.jp/problem/convolution_mod_2_64 |
| 15 | + links: |
| 16 | + - https://judge.yosupo.jp/problem/convolution_mod_2_64 |
| 17 | + bundledCode: "#line 1 \"test/convolution_mod_2_64.test.cpp\"\n#define PROBLEM \"\ |
| 18 | + https://judge.yosupo.jp/problem/convolution_mod_2_64\"\n\n#line 1 \"weilycoder/poly/karatsuba.hpp\"\ |
| 19 | + \n\n\n\n#include <algorithm>\n#include <iterator>\n#include <type_traits>\n#include\ |
| 20 | + \ <vector>\n\nnamespace weilycoder {\n/**\n * @brief Multiply two polynomials\ |
| 21 | + \ using the Karatsuba algorithm.\n * @tparam InputIt Iterator type for input polynomials.\n\ |
| 22 | + \ * @tparam OutputIt Iterator type for output polynomial.\n * @tparam Threshold\ |
| 23 | + \ Size threshold to switch to standard multiplication.\n * @param a_begin Iterator\ |
| 24 | + \ to the beginning of the first polynomial.\n * @param a_end Iterator to the end\ |
| 25 | + \ of the first polynomial.\n * @param b_begin Iterator to the beginning of the\ |
| 26 | + \ second polynomial.\n * @param b_end Iterator to the end of the second polynomial.\n\ |
| 27 | + \ * @param result_begin Iterator to the beginning of the result polynomial.\n\ |
| 28 | + \ */\ntemplate <typename InputIt, typename OutputIt, size_t Threshold = 32>\n\ |
| 29 | + void karatsuba_multiply(InputIt a_begin, InputIt a_end, InputIt b_begin, InputIt\ |
| 30 | + \ b_end,\n OutputIt result_begin) {\n using T = typename\ |
| 31 | + \ std::iterator_traits<InputIt>::value_type;\n\n static_assert(\n std::is_base_of<std::random_access_iterator_tag,\n\ |
| 32 | + \ typename std::iterator_traits<InputIt>::iterator_category>::value,\n\ |
| 33 | + \ \"karatsuba_multiply requires InputIt to be a random access iterator\"\ |
| 34 | + );\n static_assert(std::is_base_of<\n std::random_access_iterator_tag,\n\ |
| 35 | + \ typename std::iterator_traits<OutputIt>::iterator_category>::value,\n\ |
| 36 | + \ \"karatsuba_multiply requires OutputIt to be a random access\ |
| 37 | + \ iterator\");\n\n size_t a_size = std::distance(a_begin, a_end);\n size_t b_size\ |
| 38 | + \ = std::distance(b_begin, b_end);\n\n if (a_size <= Threshold || b_size <= Threshold)\ |
| 39 | + \ {\n // Base case: use standard multiplication\n for (size_t i = 0; i <\ |
| 40 | + \ a_size; ++i)\n for (size_t j = 0; j < b_size; ++j)\n result_begin[i\ |
| 41 | + \ + j] += a_begin[i] * b_begin[j];\n return;\n }\n\n size_t res_size = a_size\ |
| 42 | + \ + b_size - 1;\n size_t half_size = std::max(a_size, b_size) / 2;\n\n // Split\ |
| 43 | + \ the polynomials\n auto a_mid = (a_size > half_size) ? a_begin + half_size :\ |
| 44 | + \ a_end;\n auto b_mid = (b_size > half_size) ? b_begin + half_size : b_end;\n\ |
| 45 | + \n size_t a_low_size = std::distance(a_begin, a_mid);\n size_t b_low_size =\ |
| 46 | + \ std::distance(b_begin, b_mid);\n size_t a_high_size = std::distance(a_mid,\ |
| 47 | + \ a_end);\n size_t b_high_size = std::distance(b_mid, b_end);\n size_t a_max_size\ |
| 48 | + \ = std::max(a_low_size, a_high_size);\n size_t b_max_size = std::max(b_low_size,\ |
| 49 | + \ b_high_size);\n size_t part_size = a_max_size + b_max_size - 1;\n\n std::vector<T>\ |
| 50 | + \ z0(part_size);\n std::vector<T> z1(part_size);\n std::vector<T> z2(part_size);\n\ |
| 51 | + \n // z0 = a_low * b_low\n karatsuba_multiply(a_begin, a_mid, b_begin, b_mid,\ |
| 52 | + \ z0.begin());\n // z2 = a_high * b_high\n karatsuba_multiply(a_mid, a_end,\ |
| 53 | + \ b_mid, b_end, z2.begin());\n\n // z1 = (a_low + a_high) * (b_low + b_high)\ |
| 54 | + \ - z0 - z2\n std::vector<T> a_sum(std::max(a_low_size, a_high_size));\n for\ |
| 55 | + \ (size_t i = 0; i < a_low_size; ++i)\n a_sum[i] += a_begin[i];\n for (size_t\ |
| 56 | + \ i = 0; i < a_high_size; ++i)\n a_sum[i] += a_mid[i];\n std::vector<T> b_sum(std::max(b_low_size,\ |
| 57 | + \ b_high_size));\n for (size_t i = 0; i < b_low_size; ++i)\n b_sum[i] += b_begin[i];\n\ |
| 58 | + \ for (size_t i = 0; i < b_high_size; ++i)\n b_sum[i] += b_mid[i];\n karatsuba_multiply(a_sum.begin(),\ |
| 59 | + \ a_sum.end(), b_sum.begin(), b_sum.end(),\n z1.begin());\n\ |
| 60 | + \ for (size_t i = 0; i < part_size; ++i)\n z1[i] -= z0[i] + z2[i];\n\n //\ |
| 61 | + \ Combine results\n for (size_t i = 0; i < part_size; ++i) {\n if (i >= res_size)\n\ |
| 62 | + \ break;\n result_begin[i] += z0[i];\n }\n for (size_t i = 0; i < part_size;\ |
| 63 | + \ ++i) {\n if (i + half_size >= res_size)\n break;\n result_begin[i\ |
| 64 | + \ + half_size] += z1[i];\n }\n for (size_t i = 0; i < part_size; ++i) {\n \ |
| 65 | + \ if (i + 2 * half_size >= res_size)\n break;\n result_begin[i + 2 *\ |
| 66 | + \ half_size] += z2[i];\n }\n}\n\n/**\n * @brief Multiply two polynomials using\ |
| 67 | + \ the Karatsuba algorithm.\n * @tparam T Coefficient type of the polynomials.\n\ |
| 68 | + \ * @tparam Threshold Size threshold to switch to standard multiplication.\n *\ |
| 69 | + \ @param a First polynomial coefficients.\n * @param b Second polynomial coefficients.\n\ |
| 70 | + \ * @return Resulting polynomial coefficients after multiplication.\n */\ntemplate\ |
| 71 | + \ <typename T, size_t Threshold = 32>\nstd::vector<T> karatsuba_multiply(const\ |
| 72 | + \ std::vector<T> &a, const std::vector<T> &b) {\n using I_It = typename std::vector<T>::const_iterator;\n\ |
| 73 | + \ using O_It = typename std::vector<T>::iterator;\n std::vector<T> result(a.size()\ |
| 74 | + \ + b.size() - 1);\n karatsuba_multiply<I_It, O_It, Threshold>(a.begin(), a.end(),\ |
| 75 | + \ b.begin(), b.end(),\n result.begin());\n\ |
| 76 | + \ return result;\n}\n} // namespace weilycoder\n\n\n#line 4 \"test/convolution_mod_2_64.test.cpp\"\ |
| 77 | + \n#include <cstdint>\n#include <iostream>\n#line 7 \"test/convolution_mod_2_64.test.cpp\"\ |
| 78 | + \nusing namespace std;\nusing namespace weilycoder;\n\nint main() {\n cin.tie(nullptr)->sync_with_stdio(false);\n\ |
| 79 | + \ cin.exceptions(cin.badbit | cin.failbit);\n size_t n, m;\n cin >> n >> m;\n\ |
| 80 | + \n vector<uint64_t> a(n), b(m);\n for (size_t i = 0; i < n; ++i)\n cin >>\ |
| 81 | + \ a[i];\n for (size_t j = 0; j < m; ++j)\n cin >> b[j];\n\n auto c = karatsuba_multiply(a,\ |
| 82 | + \ b);\n for (size_t k = 0; k < n + m - 1; ++k)\n cout << c[k] << (k + 1 ==\ |
| 83 | + \ n + m - 1 ? '\\n' : ' ');\n return 0;\n}\n" |
| 84 | + code: "#define PROBLEM \"https://judge.yosupo.jp/problem/convolution_mod_2_64\"\n\ |
| 85 | + \n#include \"../weilycoder/poly/karatsuba.hpp\"\n#include <cstdint>\n#include\ |
| 86 | + \ <iostream>\n#include <vector>\nusing namespace std;\nusing namespace weilycoder;\n\ |
| 87 | + \nint main() {\n cin.tie(nullptr)->sync_with_stdio(false);\n cin.exceptions(cin.badbit\ |
| 88 | + \ | cin.failbit);\n size_t n, m;\n cin >> n >> m;\n\n vector<uint64_t> a(n),\ |
| 89 | + \ b(m);\n for (size_t i = 0; i < n; ++i)\n cin >> a[i];\n for (size_t j =\ |
| 90 | + \ 0; j < m; ++j)\n cin >> b[j];\n\n auto c = karatsuba_multiply(a, b);\n \ |
| 91 | + \ for (size_t k = 0; k < n + m - 1; ++k)\n cout << c[k] << (k + 1 == n + m\ |
| 92 | + \ - 1 ? '\\n' : ' ');\n return 0;\n}" |
| 93 | + dependsOn: |
| 94 | + - weilycoder/poly/karatsuba.hpp |
| 95 | + isVerificationFile: true |
| 96 | + path: test/convolution_mod_2_64.test.cpp |
| 97 | + requiredBy: [] |
| 98 | + timestamp: '2025-11-05 00:26:33+08:00' |
| 99 | + verificationStatus: TEST_ACCEPTED |
| 100 | + verifiedWith: [] |
| 101 | +documentation_of: test/convolution_mod_2_64.test.cpp |
| 102 | +layout: document |
| 103 | +redirect_from: |
| 104 | +- /verify/test/convolution_mod_2_64.test.cpp |
| 105 | +- /verify/test/convolution_mod_2_64.test.cpp.html |
| 106 | +title: test/convolution_mod_2_64.test.cpp |
| 107 | +--- |
0 commit comments