#include <bits/stdc++.h> using std::cin, std::cout, std::vector; using u8 = std::uint8_t; using u16 = std::uint16_t; using i32 = std::int32_t; using u32 = std::uint32_t; using u64 = std::uint64_t; using i64 = std::int64_t; #define REP(i, n) for (u32 i=0; i<(n); ++i) #define DEBUG(x) std::cerr << #x << " = " << x << "\n" void init_io() { cin.tie(nullptr); std::ios::sync_with_stdio(false); } template<class T> T power(T a, unsigned b) { T res = T(1); while(b) { if(b&1u) res *= a; b >>= 1; a = a*a; } return res; } template<unsigned MOD> class Modulo { public: Modulo(unsigned x=0):v(x) {} unsigned get() const { return v; } Modulo operator+(Modulo b) const { unsigned res = v+b.v; if (res >= MOD) res -= MOD; return res; } void operator+=(Modulo b) { *this = *this + b; } Modulo operator-(Modulo b) const { return *this + Modulo(MOD-b.v); } void operator-=(Modulo b) { *this = *this - b; } Modulo operator*(Modulo b) const { return Modulo(std::uint64_t(v) * b.v % MOD); } void operator*=(Modulo b) { *this = *this * b; } Modulo operator/(Modulo b) const { return *this * b.inverse(); } void operator/=(Modulo b) { *this = *this / b; } Modulo inverse() const { return power(*this, MOD-2); } private: unsigned v; }; // ================= using Mod = Modulo<1'000'000'007>; constexpr u32 max_n = 32; constexpr u32 max_m = 24; Mod binomial[max_n+1][max_n+1]; void calc_binomial() { binomial[0][0] = 1; for (u32 n=1; n<=max_n; ++n) { binomial[n][0] = 1; binomial[n][n] = 1; for (u32 k=1;k<n;++k) { binomial[n][k] = binomial[n-1][k-1] + binomial[n-1][k]; } } } u32 n; u32 m; u32 fixed_fractional; // (32-bit) i32 fixed_integer; void read_problem() { u32 k; cin >> n >> m >> k; n -= k; i64 fixed = 0; REP(i, k) { u32 bit = 0; char first_c = '?'; REP(j, m) { char c; cin >> c; if (j == 0) { first_c = c; } else if (bit != 0 || c != first_c) { ++bit; } const i64 val = i64(1) << (32 - bit); if (c == 'N') { fixed += val; } else if (c == 'C') { fixed -= val; } else { throw 0; } } } fixed_fractional = fixed; fixed_integer = fixed >> 32; } // phase < 3 // bit < m // remaining <= n // |integer_sum| <= n * m // carry <= 2n+1 // Memory: O(n^3 * m) // Time: O(n^4 * m^2) template <u32 phase> Mod solve_iterative(const u32 bit, const u32 remaining, const i32 integer_sum, const u32 carry); template <> Mod solve_iterative<0>(const u32 bit, const u32 remaining, const i32 integer_sum, const u32 carry); template <> Mod solve_iterative<1>(const u32 bit, const u32 remaining, const i32 integer_sum, const u32 carry); template <> Mod solve_iterative<2>(const u32 bit, const u32 remaining, const i32 integer_sum, const u32 carry); // 26 MB Mod cache[2][max_n+1][2 * max_n * max_m + 1][2 * max_n + 2]; u32 cache_current = 0; Mod solve_cached(const u32 remaining, const i32 integer_sum, const u32 carry) { return cache[cache_current][remaining][integer_sum + max_n * max_m][carry]; } void set_cache(const u32 remaining, const i32 integer_sum, const u32 carry, const Mod val) { cache[cache_current^1][remaining][integer_sum + max_n * max_m][carry] = val; } void swap_cache() { cache_current ^= 1; } // Phase 0: Add fixed bits and choose free bits. template <> Mod solve_iterative<0>(const u32 bit, const u32 remaining, const i32 integer_sum, const u32 carry) { if (bit == 0) { // All remaining heaps are +- m. const i32 sum_signed = integer_sum + i32(carry); u32 sum = sum_signed < 0 ? -sum_signed : sum_signed; if (sum % m != 0) return 0; sum /= m; // 0 <= x <= remaining // sum = x - (remaining - x) // x = (sum + remaining) / 2 sum += remaining; if (sum % 2 != 0) return 0; sum /= 2; if (sum > remaining) return 0; return binomial[remaining][sum]; } else { const u32 carry_with_fixed = carry + ((fixed_fractional >> (32-bit)) & 1u); const u32 free_bits = n - remaining; Mod total = 0; for (u32 ones = 0; ones <= free_bits; ++ones) { total += binomial[free_bits][ones] * solve_cached(remaining, integer_sum, carry_with_fixed + ones); } return total; } } // Phase 1: choose positive heaps. template <> Mod solve_iterative<1>(const u32 bit, const u32 remaining, const i32 integer_sum, const u32 carry) { Mod total = 0; for (u32 heaps = 0; heaps <= remaining; ++heaps) { total += binomial[remaining][heaps] * solve_cached(remaining-heaps, integer_sum + (m-1-bit) * heaps, carry + heaps); } return total; } // Phase 2: choose negative heaps. template <> Mod solve_iterative<2>(const u32 bit, const u32 remaining, const i32 integer_sum, const u32 carry) { Mod total = 0; for (u32 heaps = carry % 2; heaps <= remaining; heaps += 2) { total += binomial[remaining][heaps] * solve_cached(remaining-heaps, integer_sum - (m-bit) * heaps, (carry + heaps) / 2); } return total; } template <u32 phase> void solve_phase(const u32 bit) { // phase 0 REP(remaining, n+1) { const u32 max_added = (m-bit) * (n-remaining); const i32 min_integer_sum = fixed_integer - i32(max_added); const i32 max_integer_sum = fixed_integer + i32(max_added); for (i32 integer_sum = min_integer_sum; integer_sum <= max_integer_sum; ++integer_sum) { const u32 max_carry = phase == 0 ? n - remaining : 2 * (n - remaining) + 1; REP(carry, max_carry+1) { const Mod val = solve_iterative<phase>(bit, remaining, integer_sum, carry); set_cache(remaining, integer_sum, carry, val); } } } swap_cache(); } Mod solve() { solve_phase<0>(0); for (u32 bit=1; bit<m; ++bit) { solve_phase<2>(bit); solve_phase<1>(bit); solve_phase<0>(bit); } return solve_cached(n, fixed_integer, 0); } int main() { init_io(); calc_binomial(); read_problem(); const u32 n_limit = n; for (n=0; n <= n_limit; ++n) { const Mod res = solve(); cout << res.get() << ' '; } cout << "\n"; }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 | #include <bits/stdc++.h> using std::cin, std::cout, std::vector; using u8 = std::uint8_t; using u16 = std::uint16_t; using i32 = std::int32_t; using u32 = std::uint32_t; using u64 = std::uint64_t; using i64 = std::int64_t; #define REP(i, n) for (u32 i=0; i<(n); ++i) #define DEBUG(x) std::cerr << #x << " = " << x << "\n" void init_io() { cin.tie(nullptr); std::ios::sync_with_stdio(false); } template<class T> T power(T a, unsigned b) { T res = T(1); while(b) { if(b&1u) res *= a; b >>= 1; a = a*a; } return res; } template<unsigned MOD> class Modulo { public: Modulo(unsigned x=0):v(x) {} unsigned get() const { return v; } Modulo operator+(Modulo b) const { unsigned res = v+b.v; if (res >= MOD) res -= MOD; return res; } void operator+=(Modulo b) { *this = *this + b; } Modulo operator-(Modulo b) const { return *this + Modulo(MOD-b.v); } void operator-=(Modulo b) { *this = *this - b; } Modulo operator*(Modulo b) const { return Modulo(std::uint64_t(v) * b.v % MOD); } void operator*=(Modulo b) { *this = *this * b; } Modulo operator/(Modulo b) const { return *this * b.inverse(); } void operator/=(Modulo b) { *this = *this / b; } Modulo inverse() const { return power(*this, MOD-2); } private: unsigned v; }; // ================= using Mod = Modulo<1'000'000'007>; constexpr u32 max_n = 32; constexpr u32 max_m = 24; Mod binomial[max_n+1][max_n+1]; void calc_binomial() { binomial[0][0] = 1; for (u32 n=1; n<=max_n; ++n) { binomial[n][0] = 1; binomial[n][n] = 1; for (u32 k=1;k<n;++k) { binomial[n][k] = binomial[n-1][k-1] + binomial[n-1][k]; } } } u32 n; u32 m; u32 fixed_fractional; // (32-bit) i32 fixed_integer; void read_problem() { u32 k; cin >> n >> m >> k; n -= k; i64 fixed = 0; REP(i, k) { u32 bit = 0; char first_c = '?'; REP(j, m) { char c; cin >> c; if (j == 0) { first_c = c; } else if (bit != 0 || c != first_c) { ++bit; } const i64 val = i64(1) << (32 - bit); if (c == 'N') { fixed += val; } else if (c == 'C') { fixed -= val; } else { throw 0; } } } fixed_fractional = fixed; fixed_integer = fixed >> 32; } // phase < 3 // bit < m // remaining <= n // |integer_sum| <= n * m // carry <= 2n+1 // Memory: O(n^3 * m) // Time: O(n^4 * m^2) template <u32 phase> Mod solve_iterative(const u32 bit, const u32 remaining, const i32 integer_sum, const u32 carry); template <> Mod solve_iterative<0>(const u32 bit, const u32 remaining, const i32 integer_sum, const u32 carry); template <> Mod solve_iterative<1>(const u32 bit, const u32 remaining, const i32 integer_sum, const u32 carry); template <> Mod solve_iterative<2>(const u32 bit, const u32 remaining, const i32 integer_sum, const u32 carry); // 26 MB Mod cache[2][max_n+1][2 * max_n * max_m + 1][2 * max_n + 2]; u32 cache_current = 0; Mod solve_cached(const u32 remaining, const i32 integer_sum, const u32 carry) { return cache[cache_current][remaining][integer_sum + max_n * max_m][carry]; } void set_cache(const u32 remaining, const i32 integer_sum, const u32 carry, const Mod val) { cache[cache_current^1][remaining][integer_sum + max_n * max_m][carry] = val; } void swap_cache() { cache_current ^= 1; } // Phase 0: Add fixed bits and choose free bits. template <> Mod solve_iterative<0>(const u32 bit, const u32 remaining, const i32 integer_sum, const u32 carry) { if (bit == 0) { // All remaining heaps are +- m. const i32 sum_signed = integer_sum + i32(carry); u32 sum = sum_signed < 0 ? -sum_signed : sum_signed; if (sum % m != 0) return 0; sum /= m; // 0 <= x <= remaining // sum = x - (remaining - x) // x = (sum + remaining) / 2 sum += remaining; if (sum % 2 != 0) return 0; sum /= 2; if (sum > remaining) return 0; return binomial[remaining][sum]; } else { const u32 carry_with_fixed = carry + ((fixed_fractional >> (32-bit)) & 1u); const u32 free_bits = n - remaining; Mod total = 0; for (u32 ones = 0; ones <= free_bits; ++ones) { total += binomial[free_bits][ones] * solve_cached(remaining, integer_sum, carry_with_fixed + ones); } return total; } } // Phase 1: choose positive heaps. template <> Mod solve_iterative<1>(const u32 bit, const u32 remaining, const i32 integer_sum, const u32 carry) { Mod total = 0; for (u32 heaps = 0; heaps <= remaining; ++heaps) { total += binomial[remaining][heaps] * solve_cached(remaining-heaps, integer_sum + (m-1-bit) * heaps, carry + heaps); } return total; } // Phase 2: choose negative heaps. template <> Mod solve_iterative<2>(const u32 bit, const u32 remaining, const i32 integer_sum, const u32 carry) { Mod total = 0; for (u32 heaps = carry % 2; heaps <= remaining; heaps += 2) { total += binomial[remaining][heaps] * solve_cached(remaining-heaps, integer_sum - (m-bit) * heaps, (carry + heaps) / 2); } return total; } template <u32 phase> void solve_phase(const u32 bit) { // phase 0 REP(remaining, n+1) { const u32 max_added = (m-bit) * (n-remaining); const i32 min_integer_sum = fixed_integer - i32(max_added); const i32 max_integer_sum = fixed_integer + i32(max_added); for (i32 integer_sum = min_integer_sum; integer_sum <= max_integer_sum; ++integer_sum) { const u32 max_carry = phase == 0 ? n - remaining : 2 * (n - remaining) + 1; REP(carry, max_carry+1) { const Mod val = solve_iterative<phase>(bit, remaining, integer_sum, carry); set_cache(remaining, integer_sum, carry, val); } } } swap_cache(); } Mod solve() { solve_phase<0>(0); for (u32 bit=1; bit<m; ++bit) { solve_phase<2>(bit); solve_phase<1>(bit); solve_phase<0>(bit); } return solve_cached(n, fixed_integer, 0); } int main() { init_io(); calc_binomial(); read_problem(); const u32 n_limit = n; for (n=0; n <= n_limit; ++n) { const Mod res = solve(); cout << res.get() << ' '; } cout << "\n"; } |