#ifdef TODAY_KYOPRO /* */ void run() { II(N, M, Q); VI2(B, A, N); vi suma(1 << N), sumbm(1 << N), sumbq(1 << N); rep(b, 1 << N) { ll sum = 0; rep(i, N) if(b >> i & 1) { suma[b] += A[i]; sum += B[i]; } sumbm[b] = (sum <= M); sumbq[b] = (sum <= Q); } auto am = suma, aq = suma; rep(i, 1 << N) { am[i] *= sumbm[i]; aq[i] *= sumbq[i]; } am = ZetaMobius::SubsetZeta>(am); aq = ZetaMobius::SubsetZeta>(aq); ii ans = 0; rep(i, 1 << N) { ii j = ((1 << N) - 1) ^ i; chmax(ans, am[i] + aq[j]); } say(ans); } void prep() {} #else // #define MULTI //------>8-------- begin kyopro_library/template.hpp --------->8------ //------>8------ begin kyopro_library/base/include.hpp ------->8------ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace std; //------>8------- end kyopro_library/base/include.hpp -------->8------ //------>8------- begin kyopro_library/base/macro.hpp -------->8------ #define rep1(n) for(ii i = 0; i < (n); i++) #define rep2(i, n) for(ii i = 0; i < (n); i++) #define rep3(i, a, b) for(ii i = (a); i < (b); i++) #define rep4(i, a, b, c) for(ii i = (a); i < (b); i += (c)) #define rep_overload(a, b, c, d, e, ...) e #define rep(...) rep_overload(__VA_ARGS__, rep4, rep3, rep2, rep1)(__VA_ARGS__) #define per1(n) for(ii i = (n) - 1; i >= 0; i--) #define per2(i, n) for(ii i = (n) - 1; i >= 0; i--) #define per3(i, a, b) for(ii i = (b) - 1; i >= (a); i--) #define per4(i, a, b, c) for(ii i = (b) - 1; i >= (a); i -= (c)) #define per_overload(a, b, c, d, e, ...) e #define per(...) per_overload(__VA_ARGS__, per4, per3, per2, per1)(__VA_ARGS__) #define fore(x, a) for(auto &x : a) #define all(v) (v).begin(), (v).end() #define rall(v) (v).rbegin(), (v).rend() #define QYN(q, a, b) ((q) ? (a) : (b)) #define pb push_back #define eb emplace_back #define mkp make_pair #define mkt make_tuple #define fi first #define se second #define vv(type, name, a, ...) \ vector> name(a, vector(__VA_ARGS__)) #define vvv(type, name, a, b, ...) \ vector>> name( \ a, vector>(b, vector(__VA_ARGS__))) #define vvvv(type, name, a, b, c, ...) \ vector>>> name( \ a, vector>>( \ b, vector>(c, vector(__VA_ARGS__)))) #define vvvvv(type, name, a, b, c, d, ...) \ vector>>>> name( \ a, vector>>>( \ b, vector>>( \ c, vector>(d, vector(__VA_ARGS__))))) #define applyv(v, f) \ [&]() { \ auto &&_v = (v); \ for(auto &x : _v) \ f(x); \ }() #define mapv(v, f) \ [&]() { \ auto &&_v = (v); \ using Type = std::decay_t; \ std::vector ret; \ ret.reserve(_v.size()); \ for(const auto &x : _v) \ ret.push_back(f(x)); \ return ret; \ }() #define II(...) \ ii __VA_ARGS__; \ input(__VA_ARGS__) #define LL(...) \ ll __VA_ARGS__; \ input(__VA_ARGS__) #define IDX(...) \ ii __VA_ARGS__; \ input(__VA_ARGS__); \ input_index(__VA_ARGS__) #define STR(...) \ string __VA_ARGS__; \ input(__VA_ARGS__); #define CHR(...) \ char __VA_ARGS__; \ input(__VA_ARGS__); #define LD(...) \ ld __VA_ARGS__; \ input(__VA_ARGS__); #define VI(A, N) \ vector A(N); \ input(A); #define VVI(A, N, M) \ vector> A(N, vector(M)); \ input(A); #define VL(A, N) \ vector A(N); \ input(A); #define VVL(A, N, M) \ vector> A(N, vector(M)); \ input(A); #define VPI(A, N) \ vpi A(N); \ input(A); #define VTI(A, N) \ vti A(N); \ input(A); #define VI2(A, B, N) \ vector A(N), B(N); \ rep(i, N) cin >> A[i] >> B[i]; #define VL2(A, B, N) \ vector A(N), B(N); \ rep(i, N) cin >> A[i] >> B[i]; #define VI3(A, B, C, N) \ vector A(N), B(N), C(N); \ rep(i, N) cin >> A[i] >> B[i] >> C[i]; #define VL3(A, B, C, N) \ vector A(N), B(N), C(N); \ rep(i, N) cin >> A[i] >> B[i] >> C[i]; #define VST(A, N) \ vector A(N); \ input(A); #define IN2(A, B) rep(i, siz(A)) cin >> A[i] >> B[i]; #define IN3(A, B, C) rep(i, siz(A)) cin >> A[i] >> B[i] >> C[i]; #define IN4(A, B, C, D) rep(i, siz(A)) cin >> A[i] >> B[i] >> C[i] >> D[i]; #define IN5(A, B, C, D, E) \ rep(i, siz(A)) cin >> A[i] >> B[i] >> C[i] >> D[i] >> E[i]; //------>8-------- end kyopro_library/base/macro.hpp --------->8------ //------>8-------- begin kyopro_library/base/type.hpp -------->8------ using i16 = short; using i32 = int; using i64 = long long; using i128 = __int128_t; using u16 = unsigned short; using u32 = unsigned int; using u64 = unsigned long long; using u128 = __uint128_t; using f64 = double; using f80 = long double; using ii = i64; using ll = i64; using ull = u64; using vi = vector; using vvi = vector>; using vvvi = vector>>; using vl = vector; using vvl = vector>; using vvvl = vector>>; using ii3 = array; using ii4 = array; using ii5 = array; using lll = i128; using ulll = u128; constexpr lll operator""_lll(ull x) { return static_cast(x); } using ld = f80; using str = string; using vstr = vector; template using V = vector; template using VV = vector>; template using VVV = vector>>; template using VVVV = vector>>>; template using VVVVV = vector>>>>; template using VVVVVV = vector>>>>>; template using max_pq = priority_queue; template using min_pq = priority_queue, greater>; template using unset = unordered_set; template using unmap = unordered_map; template struct PR : pair { template PR(Args... args) : pair(args...) {} using pair::first; using pair::second; PR& operator+=(const PR& r) { first += r.first; second += r.second; return *this; } PR& operator-=(const PR& r) { first -= r.first; second -= r.second; return *this; } PR& operator*=(const PR& r) { first *= r.first; second *= r.second; return *this; } template PR& operator+=(const S& r) { first += r; second += r; return *this; } template PR& operator-=(const S& r) { first -= r; second -= r; return *this; } template PR& operator*=(const S& r) { first *= r; second *= r; return *this; } PR operator+(const PR& r) const { return PR(*this) += r; } PR operator-(const PR& r) const { return PR(*this) -= r; } PR operator*(const PR& r) const { return PR(*this) *= r; } template PR operator+(const S& r) const { return PR(*this) += r; } template PR operator-(const S& r) const { return PR(*this) -= r; } template PR operator*(const S& r) const { return PR(*this) *= r; } PR operator-() const { return PR{-first, -second}; } }; using pi = PR; using vpi = vector; using vvpi = vector>; using pl = PR; using vpl = vector; using vvpl = vector>; template struct TR : tuple { using tuple::tuple; T& x = get<0>(*this); U& y = get<1>(*this); V& z = get<2>(*this); TR() : tuple() {} TR(const T& a, const U& b, const V& c) : tuple(a, b, c) {} TR(const TR& other) : tuple(other), x(get<0>(*this)), y(get<1>(*this)), z(get<2>(*this)) {} TR(TR&& other) noexcept : tuple(move(other)), x(get<0>(*this)), y(get<1>(*this)), z(get<2>(*this)) {} TR& operator=(const TR& other) { tuple::operator=(other); return *this; } TR& operator=(TR&& other) noexcept { tuple::operator=(move(other)); return *this; } }; using ti = TR; using vti = vector; using vvti = vector>; using tl = TR; using vtl = vector; using vvtl = vector>; const i32 INF = 1e9 + 10; const i64 INFL = 4e18; const i128 INFLL = 1_lll << 120; template constexpr T inf = 0; template <> constexpr i32 inf = INF; template <> constexpr i64 inf = INFL; template <> constexpr i128 inf = INFLL; template <> constexpr u32 inf = INF; template <> constexpr u64 inf = INFL; template <> constexpr u128 inf = INFLL; template <> constexpr f64 inf = numeric_limits::infinity(); template <> constexpr f80 inf = numeric_limits::infinity(); istream& operator>>(istream& is, lll& x) { int c = is.peek(); while(c == ' ' || c == '\n') is.get(), c = is.peek(); bool neg = false; if(c == '-') neg = true, is.get(); x = 0; while(isdigit(is.peek())) x = x * 10 + is.get() - '0'; if(neg) x = -x; return is; } ostream& operator<<(ostream& os, lll x) { if(x < 0) os << '-', x = -x; if(x == 0) return os << '0'; string s; while(x > 0) s += x % 10 + '0', x /= 10; reverse(s.begin(), s.end()); return os << s; } #ifdef TDY lll abs(lll x) { if(x < 0) return -x; return x; } lll gcd(lll a, lll b) { while(b) a %= b, swap(a, b); return a; } #endif //------>8--------- end kyopro_library/base/type.hpp --------->8------ //------>8--------- begin kyopro_library/base/io.hpp --------->8------ const char NL = '\n'; void flush() { cout.flush(); } inline string YesNo(bool f) { return f ? "Yes" : "No"; } inline string YESNO(bool f) { return f ? "YES" : "NO"; } template istream& operator>>(istream& is, vector>& v) { for(auto& x : v) for(auto& y : x) is >> y; return is; } template istream& operator>>(istream& is, vector& v) { for(auto& x : v) is >> x; return is; } template istream& operator>>(istream& is, pair& p) { is >> p.first >> p.second; return is; } template void input(T&... a) { (cin >> ... >> a); } template void input_index(T& a) { a--; } template void input_index(T& a, Ts&... b) { a--; input_index(b...); } template ostream& operator<<(ostream& os, const pair& p) { os << p.fi << ' ' << p.se; return os; } template ostream& operator<<(ostream& os, const PR& p) { os << p.fi << ' ' << p.se; return os; } template ostream& operator<<(ostream& os, const tuple& t) { os << ' ' << get<0>(t) << ' ' << get<1>(t) << ' ' << get<2>(t); return os; } template ostream& operator<<(ostream& os, const TR& t) { os << ' ' << get<0>(t) << ' ' << get<1>(t) << ' ' << get<2>(t); return os; } template ostream& operator<<(ostream& os, const tuple& t) { os << ' ' << get<0>(t) << ' ' << get<1>(t) << ' ' << get<2>(t) << ' ' << get<3>(t); return os; } template ostream& operator<<(ostream& os, const vector>>& a) { int I = a.size(); for(int i = 0; i < I; i++) { int J = a[i].size(); for(int j = 0; j < J; j++) { int K = a[i][j].size(); for(int k = 0; k < K; k++) { os << a[i][j][k]; if(k != K - 1) os << ' '; } os << NL; } if(i != I - 1) os << NL; } return os; } template ostream& operator<<(ostream& os, const vector>& a) { int I = a.size(); for(int i = 0; i < I; i++) { int J = a[i].size(); for(int j = 0; j < J; j++) { os << a[i][j]; if(j != J - 1) os << ' '; } if(i != I - 1) cout << NL; } return os; } template ostream& operator<<(ostream& os, const vector& a) { int n = a.size(); for(int i = 0; i < n; i++) { os << a[i]; if(i != n - 1) os << ' '; } return os; } template ostream& operator<<(ostream& os, const set& a) { for(auto itr = a.begin(); itr != a.end(); itr++) { os << *itr; if(next(itr) != a.end()) os << ' '; } return os; } template ostream& operator<<(ostream& os, const multiset& a) { for(auto itr = a.begin(); itr != a.end(); itr++) { os << *itr; if(next(itr) != a.end()) os << ' '; } return os; } template ostream& operator<<(ostream& os, const deque& a) { for(auto itr = a.begin(); itr != a.end(); itr++) { os << *itr; if(next(itr) != a.end()) os << ' '; } return os; } template ostream& operator<<(ostream& os, queue a) { while(!a.empty()) { os << a.front(); a.pop(); if(a.size()) os << ' '; } return os; } template ostream& operator<<(ostream& os, priority_queue a) { while(!a.empty()) { os << a.top(); a.pop(); if(a.size()) os << ' '; } return os; } template ostream& operator<<(ostream& os, priority_queue, greater> a) { while(!a.empty()) { os << a.top(); a.pop(); if(a.size()) os << ' '; } return os; } template ostream& operator<<(ostream& os, array a) { for(int i = 0; i < N; i++) { os << a[i]; if(i != N - 1) os << ' '; } return os; } template void put(const T& a, const Ts&... b) { cout << a; (void)(cout << ... << b); } template void line(const T& a, const Ts&... b) { cout << a; (void)(cout << ... << (cout << ' ', b)); cout << ' '; } void say() { cout << '\n'; } template void say(const T& a, const Ts&... b) { cout << a; (void)(cout << ... << (cout << ' ', b)); cout << '\n'; } void esay() { #ifdef TDY cerr << endl; #endif } template void esay(const T& a, const Ts&... b) { #ifdef TDY cerr << a; (void)(cerr << ... << (cerr << ' ', b)); cerr << endl; #endif } #define O(...) \ { \ say(__VA_ARGS__); \ return; \ } //------>8---------- end kyopro_library/base/io.hpp ---------->8------ //------>8-------- begin kyopro_library/base/util.hpp -------->8------ template inline ii siz(const T& v) { return v.size(); } template A amin(A a, B b) { if(a > b) return b; return a; } template A amax(A a, B b) { if(a < b) return b; return a; } template bool chmin(A& a, B b) { if(a > b) { a = b; return true; } return false; } template bool chmax(A& a, B b) { if(a < b) { a = b; return true; } return false; } template T minv(const vector& v) { if(v.empty()) return inf; return *ranges::min_element(v); } template T maxv(const vector& v) { if(v.empty()) return -inf; return *ranges::max_element(v); } template T sumv(const vector& v) { return reduce(v.begin(), v.end()); } template ii minidx(const vector& v) { return ranges::min_element(v) - v.begin(); } template ii maxidx(const vector& v) { return ranges::max_element(v) - v.begin(); } template ii lob(const vector& v, const T& x) { return ranges::lower_bound(v, x) - v.begin(); } template ii upb(const vector& v, const T& x) { return ranges::upper_bound(v, x) - v.begin(); } template ii find(const vector& v, const T& x) { for(ii i = 0; i < siz(v); i++) if(v[i] == x) return i; return siz(v); } template ii find_last(const vector& v, const T& x) { for(ii i = siz(v) - 1; i >= 0; i--) if(v[i] == x) return i; return -1; } template void unique(vector& v) { ranges::sort(v); v.erase(unique(v.begin(), v.end()), v.end()); } template vector compress(vector v) { auto w = v; unique(w); for(T& x : v) x = lob(w, x); return v; } ii countv(const auto& a, auto v) { return count(a.begin(), a.end(), v); } void insertv(auto& a, ii idx, auto v) { assert(idx <= siz(a)); a.insert(a.begin() + idx, v); } void erasev(auto& a, ii idx) { assert(idx < siz(a)); a.erase(a.begin() + idx); } // 先頭をoffset個分後ろに void rotatebackv(auto& a, ii offset) { offset %= siz(a); rotate(a.begin(), a.end() - offset, a.end()); } // 末尾をoffset個分前の方に void rotatefrontv(auto& a, ii offset) { offset %= siz(a); rotate(a.begin(), a.begin() + offset, a.end()); } auto mkinsert(const auto& a, ii idx, auto v) { auto b = a; insertv(b, idx, v); return b; } auto mkerase(const auto& a, ii idx) { auto b = a; erasev(b, idx); return b; } auto mkpush(const auto& a, auto v) { auto b = a; b.push_back(v); return b; } template V mkslice(const V& a, ii l, ii r) { assert(l <= r && l >= 0 && r <= siz(a)); V b(a.begin() + l, a.begin() + r); return b; } template V mkconcat(const V& a, const V& b) { auto ret = a; ret.reserve(siz(a) + siz(b)); for(auto x : b) ret.push_back(x); return ret; } template vector> zip(const vector& a, const vector& b) { ii n = siz(a); vector> ret(n); for(ii i = 0; i < n; i++) ret[i] = {a[i], b[i]}; return ret; } template vector> zip(const vector& a, const vector& b, const vector& c) { ii n = siz(a); vector> ret(n); for(ii i = 0; i < n; i++) ret[i] = {a[i], b[i], c[i]}; return ret; } template PR, vector> unzip(const vector>& p) { ii n = siz(p); vector reta(n); vector retb(n); for(ii i = 0; i < n; i++) { reta[i] = p[i].first; retb[i] = p[i].second; } return mkp(reta, retb); } template TR, vector, vector> unzip(const vector>& p) { ii n = siz(p); vector reta(n); vector retb(n); vector retc(n); for(ii i = 0; i < n; i++) { auto [a, b, c] = p[i]; reta[i] = a; retb[i] = b; retc[i] = c; } return mkt(reta, retb, retc); } template T pick(max_pq& v) { T ret = v.top(); v.pop(); return ret; } template T pick(min_pq& v) { T ret = v.top(); v.pop(); return ret; } template T pick(queue& v) { T ret = v.front(); v.pop(); return ret; } template T pick(vector& v) { T ret = v.back(); v.pop_back(); return ret; } template T pickf(deque& v) { T ret = v.front(); v.pop_front(); return ret; } template T pickb(deque& v) { T ret = v.back(); v.pop_back(); return ret; } template bool nxperm(T& v) { return next_permutation(v.begin(), v.end()); } template void operator++(V& a, T) { for(auto itr = a.begin(); itr != a.end(); itr++) (*itr)++; } template void operator--(V& a, T) { for(auto itr = a.begin(); itr != a.end(); itr++) (*itr)--; } template void operator+=(V& a, auto x) { for(auto itr = a.begin(); itr != a.end(); itr++) (*itr) += x; } template void operator-=(V& a, auto x) { for(auto itr = a.begin(); itr != a.end(); itr++) (*itr) -= x; } template void operator*=(V& a, auto x) { for(auto itr = a.begin(); itr != a.end(); itr++) (*itr) *= x; } template void operator/=(V& a, auto x) { for(auto itr = a.begin(); itr != a.end(); itr++) (*itr) /= x; } template void operator%=(V& a, auto x) { for(auto itr = a.begin(); itr != a.end(); itr++) (*itr) %= x; } template T myfloor(T a, T b) { assert(b != 0); if(b < 0) a = -a, b = -b; return a / b - (a % b < 0); } template T myceil(T a, T b) { assert(b != 0); if(b < 0) a = -a, b = -b; return a / b + (a % b > 0); } template T mymod(T a, T b) { assert(b != 0); if(b < 0) b = -b; if(a > 0) return a % b; return (a % b + b) % b; } template vector mksum(const vector& v) { ii n = v.size(); vector ret(n + 1); for(ii i = 0; i < n; i++) ret[i + 1] = ret[i] + v[i]; return ret; } template vector mkpmax(const vector& v) { ii n = v.size(); vector ret(n + 1, -inf); for(ii i = 0; i < n; i++) ret[i + 1] = max(ret[i], v[i]); return ret; } template vector mkpmin(const vector& v) { ii n = v.size(); vector ret(n + 1, inf); for(ii i = 0; i < n; i++) ret[i + 1] = min(ret[i], v[i]); return ret; } vi mkiota(ii n) { vi ret(n); iota(ret.begin(), ret.end(), 0); return ret; } template V mkrev(V A) { reverse(A.begin(), A.end()); return A; } template vi mkinv(const V& A) { ii n = siz(A); vi ret(maxv(A) + 1); for(ii i = 0; i < n; i++) ret[A[i]] = i; return ret; } template vvi mkinvvec(const V& A) { ii n = siz(A); vvi ret(maxv(A) + 1); for(ii i = 0; i < n; i++) ret[A[i]].push_back(i); return ret; } template vi mkcount(const V& A) { ii n = siz(A); vi ret(maxv(A) + 1); for(ii i = 0; i < n; i++) ret[A[i]]++; return ret; } template vi argsort(const V& A) { vi idx = mkiota(siz(A)); sort(idx.begin(), idx.end(), [&](ii i, ii j) { return (A[i] == A[j] ? i < j : A[i] < A[j]); }); return idx; } template ii digsiz(T n) { ii ret = 0; while(n) { ret++; n /= 10; } return ret; } template vector digits(T n) { vector ret; while(n) { ret.push_back(n % 10); n /= 10; } reverse(ret.begin(), ret.end()); return ret; } i64 tenpow(ii r) { i64 ret = 1; while(r--) ret *= 10; return ret; } i64 intpow(i64 x, i64 r) { i64 ret = 1; while(r--) ret *= x; return ret; } template T intsqrt(T x) { ll sq = (T)sqrtl(ld(x)); while(sq * sq > x) sq--; while((sq + 1) * (sq + 1) <= x) sq++; return sq; } ii ctoi(char c) { assert('0' <= c && c <= '9'); return c - '0'; } //------>8--------- end kyopro_library/base/util.hpp --------->8------ void run(); void prep(); int main() { ios::sync_with_stdio(false); cin.tie(nullptr); cout << fixed << setprecision(15); cerr << fixed << setprecision(15); prep(); #ifdef MULTI II(T); rep(t, T) { #ifdef TDY esay("============ Case: #", t + 1, " ============"); #endif run(); } #else run(); #endif } #ifdef DEBUG #include "./debug.hpp" #else #define debug(...) #define print_line #endif //------>8--------- end kyopro_library/template.hpp ---------->8------ //------>8-- begin kyopro_library/algorithm/zeta_mobius.hpp -->8------ //------>8------- begin kyopro_library/others/bit.hpp -------->8------ /// @brief ビット演算 namespace Bit { /// @brief 1であるビットの個数を返す ii PopCount(i32 n) { return __builtin_popcount(n); } /// @brief 1であるビットの個数を返す ii PopCount(i64 n) { return __builtin_popcountll(n); } /// @brief popcountの偶奇を返す ii Parity(i32 n) { return __builtin_parity(n); } /// @brief popcountの偶奇を返す ii Parity(i64 n) { return __builtin_parityll(n); } /// @brief 最上位ビットの位置を返す ii TopBit(i32 n) { return n ? 31 - __builtin_clz(n) : -1; } /// @brief 最上位ビットの位置を返す ii TopBit(i64 n) { return n ? 63 - __builtin_clzll(n) : -1; } /// @brief 2進表現の長さを返す ii BitLength(i32 n) { return n ? 32 - __builtin_clz(n) : 1; } //// @brief 2進表現の長さを返す ii BitLength(i64 n) { return n ? 64 - __builtin_clzll(n) : 1; } /// @brief 最下位ビットの位置を返す ii LowBit(i32 n) { return n ? __builtin_ctz(n) : -1; } /// @brief 最下位ビットの位置を返す ii LowBit(i64 n) { return n ? __builtin_ctzll(n) : -1; } /// @brief 2のべき乗か否かを返す bool IsPowerOfTwo(i32 n) { return n && (n & -n) == n; } /// @brief 0~n-1ビットを立てたビットマスクを返す ll Mask(i32 n) { return (1LL << n) - 1; } /// @brief iビット目が立っているか否かを返す bool HasBit(i64 n, ii i) { return (n >> i & 1); } /// @brief sの部分集合を返す vi Subset(ii s) { vi ret; ii t = s; do { ret.push_back(t); --t &= s; } while(t != s); return ret; } /// @brief 整数nの2進表現を返す /// @param len ビット数 /// @param rev 反転するか否か string ToBinary(i64 n, ii len = 32, bool rev = false) { string ret; rep(i, len) ret += (HasBit(n, rev ? len - 1 - i : i) ? '1' : '0'); return ret; } } // namespace Bit //------>8-------- end kyopro_library/others/bit.hpp --------->8------ /// @brief ゼータ変換・メビウス変換 namespace ZetaMobius { /// @brief 高速ゼータ変換(下位集合) /// @brief V'[s] = Σ_{t⊆s} V[t] なる V' を返す /// @note |V| = 2^N として O(N 2^N) template vector SubsetZeta(vector V) { int N = Bit::TopBit((int)V.size()); rep(i, N) rep(j, 1 << N) { if(j >> i & 1) V[j] = Monoid::op(V[j], V[j ^ (1 << i)]); } return V; } /// @brief 高速ゼータ変換(上位集合) /// @brief V'[s] = Σ_{t⊇s} V[t] なる V' を返す /// @note |V| = 2^N として O(N 2^N) template vector SupersetZeta(vector V) { int N = Bit::TopBit((int)V.size()); rep(i, N) rep(j, 1 << N) { if(~j >> i & 1) V[j] = Monoid::op(V[j], V[j ^ (1 << i)]); } return V; } /// @brief 高速メビウス変換(下位集合) /// @brief V[s] = Σ_{t⊆s} V'[t] なる V' を返す /// @note 逆変換が必要なので、v は可換群の元である必要がある /// @note |V| = 2^N として O(N 2^N) template vector SubsetMobius(vector V) { int N = Bit::TopBit((int)V.size()); rep(i, N) rep(j, 1 << N) { if(j >> i & 1) V[j] = Abel::op(V[j], Abel::inv(V[j ^ (1 << i)])); } return V; } /// @brief 高速メビウス変換(上位集合) /// @brief V[s] = Σ_{t⊇s} V'[t] なる V' を返す /// @note 逆変換が必要なので、v は可換群の元である必要がある /// @note |V| = 2^N として O(N 2^N) template vector SupersetMobius(vector V) { int N = Bit::TopBit((int)V.size()); rep(i, N) rep(j, 1 << N) { if(~j >> i & 1) V[j] = Abel::op(V[j], Abel::inv(V[j ^ (1 << i)])); } return V; } } // namespace ZetaMobius /// @brief 畳み込み namespace ConvolutionBit { template vector OrConvolution( vector A, vector B) { using Type = typename Ring::Type; int N = max(A.size(), B.size()); struct Abel { using Type = typename Ring::Type; static Type op(const Type& l, const Type& r) { return Ring::plus(l, r); } static Type inv(const Type& x) { return Ring::inv(x); } static Type id() { return Ring::zero(); } }; A = move(ZetaMobius::SubsetZeta(A)); B = move(ZetaMobius::SubsetZeta(B)); rep(i, N) A[i] = Ring::mul(A[i], B[i]); A = move(ZetaMobius::SubsetMobius(A)); return A; } template vector AndConvolution( vector A, vector B) { using Type = typename Ring::Type; int N = max(A.size(), B.size()); struct Abel { using Type = typename Ring::Type; static Type op(const Type& l, const Type& r) { return Ring::plus(l, r); } static Type inv(const Type& x) { return Ring::inv(x); } static Type id() { return Ring::zero(); } }; A = move(ZetaMobius::SupersetZeta(A)); B = move(ZetaMobius::SupersetZeta(B)); rep(i, N) A[i] = Ring::mul(A[i], B[i]); A = move(ZetaMobius::SupersetMobius(A)); return A; } template vector SubsetConvolution( vector A, vector B) { using Type = typename Ring::Type; int N = max(A.size(), B.size()); int M = Bit::TopBit(N); vector> A2(M + 1, vector(N)), B2 = A2; rep(i, N) { A2[Bit::PopCount(i)][i] = A[i]; B2[Bit::PopCount(i)][i] = B[i]; } struct Abel { using Type = typename Ring::Type; static Type op(const Type& l, const Type& r) { return Ring::plus(l, r); } static Type inv(const Type& x) { return Ring::inv(x); } static Type id() { return Ring::zero(); } }; rep(i, M + 1) { A2[i] = move(ZetaMobius::SubsetZeta(A2[i])); B2[i] = move(ZetaMobius::SubsetZeta(B2[i])); } vector> conv(M + 1, vector(N)); for(int i = 0; i <= M; i++) for(int j = 0; i + j <= M; j++) { rep(k, N) conv[i + j][k] = Ring::plus(conv[i + j][k], Ring::mul(A2[i][k], B2[j][k])); } rep(i, M + 1) conv[i] = move(ZetaMobius::SubsetMobius(conv[i])); rep(i, N) A[i] = conv[Bit::PopCount(i)][i]; return A; } } // namespace ConvolutionBit //------>8------ begin kyopro_library/others/monoid.hpp ------>8------ /// @brief モノイド namespace Monoid { /// @brief Minモノイド /// @tparam max_value 単位元 template struct Min { using Type = T; static Type id() { return max_value; } static Type op(const Type& a, const Type& b) { return min(a, b); } }; /// @brief Maxモノイド /// @tparam min_value 単位元 template struct Max { using Type = T; static Type id() { return min_value; } static Type op(const Type& a, const Type& b) { return max(a, b); } }; /// @brief 和 template struct Sum { using Type = T; static Type id() { return 0; } static Type op(const Type& a, const Type& b) { return a + b; } }; /// @brief (和,区間の長さ) template struct SumPair { using Type = pair; static Type id() { return make_pair(T(0), 0); } static Type op(const Type& a, const Type& b) { return {a.first + b.first, a.second + b.second}; } }; template struct Update { using Type = T; static Type id() { return not_exist; } static Type op(const Type& a, const Type& b) { return b == id() ? a : b; } }; } // namespace Monoid //------>8------- end kyopro_library/others/monoid.hpp ------->8------ //------>8------- begin kyopro_library/others/abel.hpp ------->8------ /// @brief 可換群 namespace Abel { /// @brief 和 template struct Sum { using Type = T; static Type id() { return T(0); } static Type op(const Type& a, const Type& b) { return a + b; } static Type inv(const Type& x) { return -x; } }; template struct Prod { using Type = T; static Type id() { return T(1); } static Type op(const Type& a, const Type& b) { return a * b; } static Type inv(const Type& x) { return Type(1) / x; } }; /// @brief XOR template struct Xor { using Type = T; static Type id() { return T(0); } static Type op(const Type& a, const Type& b) { return a ^ b; } static Type inv(const Type& x) { return x; } }; } // namespace Abel //------>8-------- end kyopro_library/others/abel.hpp -------->8------ //------>8------- begin kyopro_library/others/ring.hpp ------->8------ /// @brief 環・半環 namespace Ring { template struct PlusMul { using Type = T; static Type plus(const Type& l, const Type& r) { return l + r; } static Type inv(const Type& x) { return -x; } static Type mul(const Type& l, const Type& r) { return l * r; } static Type zero() { return 0; } static Type one() { return 1; } }; template struct MinPlus { using Type = T; static Type plus(const Type& l, const Type& r) { return min(l, r); } static Type mul(const Type& l, const Type& r) { return l + r; } static Type zero() { return max_value; } static Type one() { return 0; } }; template struct MaxPlus { using Type = T; static Type plus(const Type& l, const Type& r) { return max(l, r); } static Type mul(const Type& l, const Type& r) { return l + r; } static Type zero() { return min_value; } static Type one() { return 0; } }; } // namespace Ring //------>8-------- end kyopro_library/others/ring.hpp -------->8------ //------>8--- end kyopro_library/algorithm/zeta_mobius.hpp --->8------ // #include #define TODAY_KYOPRO #include __FILE__ #endif // g.cpp