This documentation is automatically generated by online-judge-tools/verification-helper
View the Project on GitHub fffelix-huang/CP-stuff
#include "library/convolution/subset-convolution.hpp"
#pragma once #include <vector> #include <algorithm> #include <cassert> #include "../misc/type-traits.hpp" namespace felix { template<class T, class F> void fwht(std::vector<T>& a, F f) { const int n = (int) a.size(); assert(__builtin_popcount(n) == 1); for(int i = 1; i < n; i <<= 1) { for(int j = 0; j < n; j += i << 1) { for(int k = 0; k < i; k++) { f(a[j + k], a[i + j + k]); } } } } template<class T> void or_transform(std::vector<T>& a, bool inv) { fwht(a, [&](T& x, T& y) { y += x * (inv ? -1 : +1); }); } template<class T> void and_transform(std::vector<T>& a, bool inv) { fwht(a, [&](T& x, T& y) { x += y * (inv ? -1 : +1); }); } template<class T> void xor_transform(std::vector<T>& a, bool inv) { fwht(a, [](T& x, T& y) { T z = x + y; y = x - y; x = z; }); if(inv) { if constexpr(internal::is_integral<T>::value) { for(auto& x : a) { x /= a.size(); } } else { T z = T(1) / T(a.size()); for(auto& x : a) { x *= z; } } } } template<class T> std::vector<T> or_convolution(std::vector<T> a, std::vector<T> b) { assert(a.size() == b.size()); or_transform(a, false); or_transform(b, false); for(int i = 0; i < (int) a.size(); i++) { a[i] *= b[i]; } or_transform(a, true); return a; } template<class T> std::vector<T> and_convolution(std::vector<T> a, std::vector<T> b) { assert(a.size() == b.size()); and_transform(a, false); and_transform(b, false); for(int i = 0; i < (int) a.size(); i++) { a[i] *= b[i]; } and_transform(a, true); return a; } template<class T> std::vector<T> xor_convolution(std::vector<T> a, std::vector<T> b) { assert(a.size() == b.size()); xor_transform(a, false); xor_transform(b, false); for (int i = 0; i < (int) a.size(); i++) { a[i] *= b[i]; } xor_transform(a, true); return a; } template<class T> std::vector<T> subset_convolution(const std::vector<T>& f, const std::vector<T>& g) { assert(f.size() == g.size()); const int n = (int) f.size(); assert(__builtin_popcount(n) == 1); const int lg = std::__lg(n); std::vector<std::vector<T>> fhat(lg + 1, std::vector<T>(n)), ghat(fhat), h(fhat); for(int mask = 0; mask < n; mask++) { fhat[__builtin_popcount(mask)][mask] = f[mask]; ghat[__builtin_popcount(mask)][mask] = g[mask]; } for(int i = 0; i <= lg; ++i) { or_transform(fhat[i], false); or_transform(ghat[i], false); } for(int mask = 0; mask < n; mask++) { for(int i = 0; i <= lg; ++i) { for(int j = 0; j <= i; ++j) { h[i][mask] += fhat[j][mask] * ghat[i - j][mask]; } } } for(int i = 0; i <= lg; ++i) { or_transform(h[i], true); } std::vector<T> result(n); for(int mask = 0; mask < n; mask++) { result[mask] = h[__builtin_popcount(mask)][mask]; } return result; } } // namespace felix
#line 2 "library/convolution/subset-convolution.hpp" #include <vector> #include <algorithm> #include <cassert> #line 3 "library/misc/type-traits.hpp" #include <numeric> #include <type_traits> namespace felix { namespace internal { #ifndef _MSC_VER template<class T> using is_signed_int128 = typename std::conditional<std::is_same<T, __int128_t>::value || std::is_same<T, __int128>::value, std::true_type, std::false_type>::type; template<class T> using is_unsigned_int128 = typename std::conditional<std::is_same<T, __uint128_t>::value || std::is_same<T, unsigned __int128>::value, std::true_type, std::false_type>::type; template<class T> using make_unsigned_int128 = typename std::conditional<std::is_same<T, __int128_t>::value, __uint128_t, unsigned __int128>; template<class T> using is_integral = typename std::conditional<std::is_integral<T>::value || is_signed_int128<T>::value || is_unsigned_int128<T>::value, std::true_type, std::false_type>::type; template<class T> using is_signed_int = typename std::conditional<(is_integral<T>::value && std::is_signed<T>::value) || is_signed_int128<T>::value, std::true_type, std::false_type>::type; template<class T> using is_unsigned_int = typename std::conditional<(is_integral<T>::value && std::is_unsigned<T>::value) || is_unsigned_int128<T>::value, std::true_type, std::false_type>::type; template<class T> using to_unsigned = typename std::conditional<is_signed_int128<T>::value, make_unsigned_int128<T>, typename std::conditional<std::is_signed<T>::value, std::make_unsigned<T>, std::common_type<T>>::type>::type; #else template<class T> using is_integral = typename std::is_integral<T>; template<class T> using is_signed_int = typename std::conditional<is_integral<T>::value && std::is_signed<T>::value, std::true_type, std::false_type>::type; template<class T> using is_unsigned_int = typename std::conditional<is_integral<T>::value && std::is_unsigned<T>::value, std::true_type, std::false_type>::type; template<class T> using to_unsigned = typename std::conditional<is_signed_int<T>::value, std::make_unsigned<T>, std::common_type<T>>::type; #endif template<class T> using is_signed_int_t = std::enable_if_t<is_signed_int<T>::value>; template<class T> using is_unsigned_int_t = std::enable_if_t<is_unsigned_int<T>::value>; template<class T> using to_unsigned_t = typename to_unsigned<T>::type; template<class T> struct safely_multipliable {}; template<> struct safely_multipliable<short> { using type = int; }; template<> struct safely_multipliable<unsigned short> { using type = unsigned int; }; template<> struct safely_multipliable<int> { using type = long long; }; template<> struct safely_multipliable<unsigned int> { using type = unsigned long long; }; template<> struct safely_multipliable<long long> { using type = __int128; }; template<> struct safely_multipliable<unsigned long long> { using type = __uint128_t; }; template<class T> using safely_multipliable_t = typename safely_multipliable<T>::type; } // namespace internal } // namespace felix #line 6 "library/convolution/subset-convolution.hpp" namespace felix { template<class T, class F> void fwht(std::vector<T>& a, F f) { const int n = (int) a.size(); assert(__builtin_popcount(n) == 1); for(int i = 1; i < n; i <<= 1) { for(int j = 0; j < n; j += i << 1) { for(int k = 0; k < i; k++) { f(a[j + k], a[i + j + k]); } } } } template<class T> void or_transform(std::vector<T>& a, bool inv) { fwht(a, [&](T& x, T& y) { y += x * (inv ? -1 : +1); }); } template<class T> void and_transform(std::vector<T>& a, bool inv) { fwht(a, [&](T& x, T& y) { x += y * (inv ? -1 : +1); }); } template<class T> void xor_transform(std::vector<T>& a, bool inv) { fwht(a, [](T& x, T& y) { T z = x + y; y = x - y; x = z; }); if(inv) { if constexpr(internal::is_integral<T>::value) { for(auto& x : a) { x /= a.size(); } } else { T z = T(1) / T(a.size()); for(auto& x : a) { x *= z; } } } } template<class T> std::vector<T> or_convolution(std::vector<T> a, std::vector<T> b) { assert(a.size() == b.size()); or_transform(a, false); or_transform(b, false); for(int i = 0; i < (int) a.size(); i++) { a[i] *= b[i]; } or_transform(a, true); return a; } template<class T> std::vector<T> and_convolution(std::vector<T> a, std::vector<T> b) { assert(a.size() == b.size()); and_transform(a, false); and_transform(b, false); for(int i = 0; i < (int) a.size(); i++) { a[i] *= b[i]; } and_transform(a, true); return a; } template<class T> std::vector<T> xor_convolution(std::vector<T> a, std::vector<T> b) { assert(a.size() == b.size()); xor_transform(a, false); xor_transform(b, false); for (int i = 0; i < (int) a.size(); i++) { a[i] *= b[i]; } xor_transform(a, true); return a; } template<class T> std::vector<T> subset_convolution(const std::vector<T>& f, const std::vector<T>& g) { assert(f.size() == g.size()); const int n = (int) f.size(); assert(__builtin_popcount(n) == 1); const int lg = std::__lg(n); std::vector<std::vector<T>> fhat(lg + 1, std::vector<T>(n)), ghat(fhat), h(fhat); for(int mask = 0; mask < n; mask++) { fhat[__builtin_popcount(mask)][mask] = f[mask]; ghat[__builtin_popcount(mask)][mask] = g[mask]; } for(int i = 0; i <= lg; ++i) { or_transform(fhat[i], false); or_transform(ghat[i], false); } for(int mask = 0; mask < n; mask++) { for(int i = 0; i <= lg; ++i) { for(int j = 0; j <= i; ++j) { h[i][mask] += fhat[j][mask] * ghat[i - j][mask]; } } } for(int i = 0; i <= lg; ++i) { or_transform(h[i], true); } std::vector<T> result(n); for(int mask = 0; mask < n; mask++) { result[mask] = h[__builtin_popcount(mask)][mask]; } return result; } } // namespace felix