src/math/nim_prod/lib.hpp
| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | #pragma once | ||
| 2 | |||
| 3 | #include "../../util/alias/num/lib.hpp" | ||
| 4 | |||
| 5 | namespace tifa_libs { | ||
| 6 | namespace nim_prod_impl_ { | ||
| 7 | struct calc8 { | ||
| 8 | // NOLINTNEXTLINE(modernize-avoid-c-arrays) | ||
| 9 | u16 dp[1 << 8][1 << 8]{}; | ||
| 10 | CEXPE calc8() NE { | ||
| 11 | dp[0][0] = dp[0][1] = dp[1][0] = 0, dp[1][1] = 1; | ||
| 12 | flt_ (u32, e, 1, 4) { | ||
| 13 | cu32 p = 1 << e, q = p >> 1; | ||
| 14 | cu16 ep = u16(1u << p), eq = u16(1u << q); | ||
| 15 | flt_ (u16, i, 0, ep) | ||
| 16 | flt_ (u16, j, i, ep) { | ||
| 17 | if (i < eq && j < eq) continue; | ||
| 18 | if (std::min(i, j) <= 1u) { | ||
| 19 | dp[i][j] = dp[j][i] = i * j; | ||
| 20 | continue; | ||
| 21 | } | ||
| 22 | cu16 iu = u16(i >> q), il = u16(i & (eq - 1)), ju = u16(j >> q), jl = u16(j & (eq - 1)); | ||
| 23 | cu16 u = dp[iu][ju], l = dp[il][jl], ul = dp[iu ^ il][ju ^ jl], uq = dp[u][eq >> 1]; | ||
| 24 | dp[i][j] = u16((ul ^ l) << q) ^ uq ^ l, dp[j][i] = dp[i][j]; | ||
| 25 | } | ||
| 26 | } | ||
| 27 | } | ||
| 28 | } CEXP c8; | ||
| 29 | |||
| 30 | struct calc16 { | ||
| 31 | static CEXP u16 proot = 10279; | ||
| 32 | static CEXP u32 ppoly = 92191, order = 65535; | ||
| 33 | |||
| 34 | // NOLINTNEXTLINE(modernize-avoid-c-arrays) | ||
| 35 | u16 base[16]{}, exp[(1 << 18) + 100]{}; | ||
| 36 | // NOLINTNEXTLINE(modernize-avoid-c-arrays) | ||
| 37 | u32 log[1 << 16]{}; | ||
| 38 | |||
| 39 | private: | ||
| 40 | CEXP u16 d(u32 x) NE { | ||
| 41 | auto _ = x < 32768u ? 0 : ppoly; | ||
| 42 | return u16((x << 1) ^ _); | ||
| 43 | } | ||
| 44 | CEXP u16 naive(u16 i, u16 j) NE { | ||
| 45 | if (min(i, j) <= 1u) return i * j; | ||
| 46 | cu16 q = 8, eq = 1u << 8; | ||
| 47 | cu16 iu = u16(i >> q), il = u16(i & (eq - 1)), ju = u16(j >> q), jl = u16(j & (eq - 1)); | ||
| 48 | cu16 u = c8.dp[iu][ju], l = c8.dp[il][jl], ul = c8.dp[iu ^ il][ju ^ jl], uq = c8.dp[u][eq >> 1]; | ||
| 49 | return u16((ul ^ l) << q) ^ uq ^ l; | ||
| 50 | } | ||
| 51 | |||
| 52 | public: | ||
| 53 | CEXPE calc16() NE { | ||
| 54 | base[0] = 1; | ||
| 55 | flt_ (u32, i, 1, 16) base[i] = naive(base[i - 1], proot); | ||
| 56 | exp[0] = 1; | ||
| 57 | flt_ (u32, i, 1, order) exp[i] = d(exp[i - 1]); | ||
| 58 | u16* pre = exp + order + 1; | ||
| 59 | pre[0] = 0; | ||
| 60 | flt_ (u32, b, 0, 16) { | ||
| 61 | cu32 is = 1 << b; | ||
| 62 | flt_ (u32, i, is, is * 2) pre[i] = pre[i - is] ^ base[b]; | ||
| 63 | } | ||
| 64 | flt_ (u32, i, 0, order) exp[i] = pre[exp[i]], log[exp[i]] = i; | ||
| 65 | cu32 ie_ = 2 * order + 30; | ||
| 66 | flt_ (u32, i, order, ie_) exp[i] = exp[i - order]; | ||
| 67 | for (u32 i = ie_; i < sizeof(exp) / sizeof(u16); ++i) exp[i] = 0; | ||
| 68 | log[0] = ie_ + 1; | ||
| 69 | } | ||
| 70 | 219988866 | ND CEXP u16 prod(u16 i, u16 j) CNE { return exp[log[i] + log[j]]; } | |
| 71 | // exp[3] = 2^{15} = 32768 | ||
| 72 | 109994433 | ND CEXP u16 Hprod(u16 i, u16 j) CNE { return exp[log[i] + log[j] + 3]; } | |
| 73 | 36664811 | ND CEXP u16 H(u16 i) CNE { return exp[log[i] + 3]; } | |
| 74 | 36664811 | ND CEXP u16 H2(u16 i) CNE { return exp[log[i] + 6]; } | |
| 75 | } CEXP c16; | ||
| 76 | |||
| 77 | CEXP u16 nimprod16(u16 i, u16 j) NE { return c16.prod(i, j); } | ||
| 78 | 109994433 | CEXP u32 nimprod32(u32 i, u32 j) NE { | |
| 79 | 109994433 | cu16 iu = u16(i >> 16), il = u16(i & 65535), ju = u16(j >> 16), jl = u16(j & 65535); | |
| 80 | 109994433 | cu16 l = c16.prod(il, jl), ul = c16.prod(iu ^ il, ju ^ jl), uq = c16.Hprod(iu, ju); | |
| 81 | 109994433 | return (u32(ul ^ l) << 16) ^ uq ^ l; | |
| 82 | } | ||
| 83 | |||
| 84 | // (+ : xor, x : nim product, * : integer product) | ||
| 85 | // i x j | ||
| 86 | // = (iu x ju + il x ju + iu x ji) * 2^{16} | ||
| 87 | // + (iu x ju x 2^{15}) + il x jl | ||
| 88 | // (assign ju = 2^{15}, jl = 0) | ||
| 89 | // = ((iu + il) x 2^{15}) * 2^{16} + (iu x 2^{15} x 2^{15}) | ||
| 90 | 36664811 | CEXP u32 H(u32 i) NE { | |
| 91 | 36664811 | cu16 iu = u16(i >> 16), il = u16(i & 65535); | |
| 92 | 36664811 | return (u32(c16.H(iu ^ il)) << 16) ^ c16.H2(iu); | |
| 93 | } | ||
| 94 | 36664811 | CEXP u64 nimprod64(u64 i, u64 j) NE { | |
| 95 | 36664811 | cu32 iu = u32(i >> 32), il = u32(i & u32(-1)), ju = u32(j >> 32), jl = u32(j & u32(-1)); | |
| 96 | 36664811 | cu32 l = nimprod32(il, jl), ul = nimprod32(iu ^ il, ju ^ jl), uq = H(nimprod32(iu, ju)); | |
| 97 | 36664811 | return (u64(ul ^ l) << 32) ^ uq ^ l; | |
| 98 | } | ||
| 99 | } // namespace nim_prod_impl_ | ||
| 100 | |||
| 101 | using nim_prod_impl_::nimprod16, nim_prod_impl_::nimprod32, nim_prod_impl_::nimprod64; | ||
| 102 | |||
| 103 | } // namespace tifa_libs | ||
| 104 |