|
| 1 | +// Time: O(9 * (9 * n / 2) * (n / 2)) = O(n^2) |
| 2 | +// Space: O((9 * n / 2) * (n / 2)) = O(n^2) |
| 3 | + |
| 4 | +// dp, combinatorics |
| 5 | +class Solution { |
| 6 | +public: |
| 7 | + int countBalancedPermutations(string num) { |
| 8 | + static const uint32_t MOD = 1e9 + 7; |
| 9 | + vector<int> fact = {1, 1}; |
| 10 | + vector<int> inv = {1, 1}; |
| 11 | + vector<int> inv_fact = {1, 1}; |
| 12 | + const auto& lazy_init = [&](int n) { |
| 13 | + while (size(inv) <= n) { // lazy initialization |
| 14 | + fact.emplace_back((static_cast<int64_t>(fact.back()) * size(inv)) % MOD); |
| 15 | + inv.emplace_back((static_cast<int64_t>(inv[MOD % size(inv)]) * (MOD - MOD / size(inv))) % MOD); // https://cp-algorithms.com/algebra/module-inverse.html |
| 16 | + inv_fact.emplace_back((static_cast<int64_t>(inv_fact.back()) * inv.back()) % MOD); |
| 17 | + } |
| 18 | + }; |
| 19 | + |
| 20 | + const auto& nCr = [&](int n, int k) { |
| 21 | + lazy_init(n); |
| 22 | + return (((static_cast<int64_t>(fact[n]) * inv_fact[n - k]) % MOD) * inv_fact[k]) % MOD; |
| 23 | + }; |
| 24 | + |
| 25 | + const auto& factorial = [&](int n) { |
| 26 | + lazy_init(n); |
| 27 | + return fact[n]; |
| 28 | + }; |
| 29 | + |
| 30 | + const auto& inv_factorial = [&](int n) { |
| 31 | + lazy_init(n); |
| 32 | + return inv_fact[n]; |
| 33 | + }; |
| 34 | + |
| 35 | + int total = accumulate(cbegin(num), cend(num), 0, [](const auto& accu, const auto& x) { |
| 36 | + return accu + (x - '0'); |
| 37 | + }); |
| 38 | + if (total % 2) { |
| 39 | + return 0; |
| 40 | + } |
| 41 | + total /= 2; |
| 42 | + vector<int> cnt(26); |
| 43 | + for (const auto& x : num) { |
| 44 | + ++cnt[x - '0']; |
| 45 | + } |
| 46 | + const int even = size(num) / 2; |
| 47 | + vector<vector<int>> dp(total + 1, vector<int>(even + 1)); |
| 48 | + dp[0][0] = 1; |
| 49 | + for (int i = 0; i < size(cnt); ++i) { |
| 50 | + if (!cnt[i]) { |
| 51 | + continue; |
| 52 | + } |
| 53 | + for (int j = total; j >= 0; --j) { |
| 54 | + for (int k = even; k >= 0; --k) { |
| 55 | + if (!dp[j][k]) { |
| 56 | + continue; |
| 57 | + } |
| 58 | + for (int c = 1; c <= cnt[i]; ++c) { |
| 59 | + if (j + c * i <= total && k + c <= even) { |
| 60 | + dp[j + c * i][k + c] = (dp[j + c * i][k + c] + ((static_cast<int64_t>(dp[j][k]) * nCr(cnt[i], c)) % MOD)) % MOD; |
| 61 | + } |
| 62 | + } |
| 63 | + } |
| 64 | + } |
| 65 | + } |
| 66 | + int result = (((static_cast<int64_t>(dp[total][even]) * factorial(even)) % MOD) * factorial(size(num) - even)) % MOD; |
| 67 | + for (const auto& x : cnt) { |
| 68 | + result = (static_cast<int64_t>(result) * inv_factorial(x)) % MOD; |
| 69 | + } |
| 70 | + return result; |
| 71 | + } |
| 72 | +}; |
0 commit comments