|  | 
| 1 | 1 | package g3301_3400.s3343_count_number_of_balanced_permutations; | 
| 2 | 2 | 
 | 
| 3 |  | -// #Hard #2024_11_04_Time_182_ms_(100.00%)_Space_45.6_MB_(100.00%) | 
| 4 |  | - | 
| 5 |  | -import java.util.ArrayList; | 
| 6 |  | -import java.util.HashMap; | 
| 7 |  | -import java.util.List; | 
| 8 |  | -import java.util.Map; | 
|  | 3 | +// #Hard #2024_11_05_Time_61_ms_(97.56%)_Space_44.3_MB_(100.00%) | 
| 9 | 4 | 
 | 
| 10 | 5 | public class Solution { | 
| 11 |  | -    private static final long M = 1000000007; | 
| 12 |  | -    private int[] freq; | 
|  | 6 | +    private static final int M = 1000000007; | 
| 13 | 7 | 
 | 
| 14 |  | -    public int countBalancedPermutations(String num) { | 
| 15 |  | -        int[] freq = new int[10]; | 
| 16 |  | -        int sum = 0; | 
| 17 |  | -        for (int i = 0; i < num.length(); i++) { | 
| 18 |  | -            int v = num.charAt(i) - '0'; | 
| 19 |  | -            freq[v]++; | 
| 20 |  | -            sum += v; | 
| 21 |  | -        } | 
| 22 |  | -        if (sum % 2 == 1) { | 
| 23 |  | -            return 0; | 
|  | 8 | +    public int countBalancedPermutations(String n) { | 
|  | 9 | +        int l = n.length(); | 
|  | 10 | +        int ts = 0; | 
|  | 11 | +        int[] c = new int[10]; | 
|  | 12 | +        for (char d : n.toCharArray()) { | 
|  | 13 | +            c[d - '0']++; | 
|  | 14 | +            ts += d - '0'; | 
| 24 | 15 |         } | 
| 25 |  | -        sum /= 2; | 
| 26 |  | -        this.freq = freq; | 
| 27 |  | -        int evenCount = num.length() / 2; | 
| 28 |  | -        int oddCount = num.length() - evenCount; | 
| 29 |  | -        return (int) countAll(9, evenCount, oddCount, sum, sum); | 
| 30 |  | -    } | 
| 31 |  | - | 
| 32 |  | -    private final Map<Long, Long> cache = new HashMap<>(); | 
| 33 |  | - | 
| 34 |  | -    private long countAll( | 
| 35 |  | -            int idx, int evenLeftCount, int oddLeftCount, int evenLeftSum, int oddLeftSum) { | 
| 36 |  | -        if (evenLeftCount < 0 || oddLeftCount < 0 || evenLeftSum < 0 || oddLeftSum < 0) { | 
|  | 16 | +        if (ts % 2 != 0) { | 
| 37 | 17 |             return 0; | 
| 38 | 18 |         } | 
| 39 |  | -        if (idx == -1) { | 
| 40 |  | -            if (evenLeftCount == 0 && oddLeftCount == 0) { | 
| 41 |  | -                return 1; | 
| 42 |  | -            } | 
| 43 |  | -            return 0; | 
|  | 19 | +        int hs = ts / 2; | 
|  | 20 | +        int m = (l + 1) / 2; | 
|  | 21 | +        long[] f = new long[l + 1]; | 
|  | 22 | +        f[0] = 1; | 
|  | 23 | +        for (int i = 1; i <= l; i++) { | 
|  | 24 | +            f[i] = f[i - 1] * i % M; | 
| 44 | 25 |         } | 
| 45 |  | -        long key = (((long) evenLeftCount) << 48) + (((long) evenLeftSum) << 32) + idx; | 
| 46 |  | -        if (cache.containsKey(key)) { | 
| 47 |  | -            return cache.get(key); | 
|  | 26 | +        long[] invF = new long[l + 1]; | 
|  | 27 | +        invF[l] = modInverse(f[l], M); | 
|  | 28 | +        for (int i = l - 1; i >= 0; i--) { | 
|  | 29 | +            invF[i] = invF[i + 1] * (i + 1) % M; | 
| 48 | 30 |         } | 
| 49 |  | -        long total = 0; | 
| 50 |  | -        for (int i = 0; i <= freq[idx]; i++) { | 
| 51 |  | -            int j = freq[idx] - i; | 
| 52 |  | -            long c = | 
| 53 |  | -                    countAll( | 
| 54 |  | -                            idx - 1, | 
| 55 |  | -                            evenLeftCount - i, | 
| 56 |  | -                            oddLeftCount - j, | 
| 57 |  | -                            evenLeftSum - i * idx, | 
| 58 |  | -                            oddLeftSum - j * idx); | 
| 59 |  | -            if (c == 0) { | 
|  | 31 | +        long[][] dp = new long[m + 1][hs + 1]; | 
|  | 32 | +        dp[0][0] = 1; | 
|  | 33 | +        for (int d = 0; d <= 9; d++) { | 
|  | 34 | +            if (c[d] == 0) { | 
| 60 | 35 |                 continue; | 
| 61 | 36 |             } | 
| 62 |  | -            c = (c * choose(evenLeftCount, i)) % M; | 
| 63 |  | -            c = (c * choose(oddLeftCount, j)) % M; | 
| 64 |  | -            total = (total + c) % M; | 
|  | 37 | +            for (int k = m; k >= 0; k--) { | 
|  | 38 | +                for (int s = hs; s >= 0; s--) { | 
|  | 39 | +                    if (dp[k][s] == 0) { | 
|  | 40 | +                        continue; | 
|  | 41 | +                    } | 
|  | 42 | +                    for (int t = 1; t <= c[d] && k + t <= m && s + d * t <= hs; t++) { | 
|  | 43 | +                        dp[k + t][s + d * t] = | 
|  | 44 | +                                (dp[k + t][s + d * t] + dp[k][s] * comb(c[d], t, f, invF, M)) % M; | 
|  | 45 | +                    } | 
|  | 46 | +                } | 
|  | 47 | +            } | 
| 65 | 48 |         } | 
| 66 |  | -        cache.put(key, total); | 
| 67 |  | -        return total; | 
| 68 |  | -    } | 
| 69 |  | - | 
| 70 |  | -    private static final List<long[]> LONGS = new ArrayList<>(); | 
| 71 |  | - | 
| 72 |  | -    static { | 
| 73 |  | -        LONGS.add(new long[] {1}); | 
|  | 49 | +        long w = dp[m][hs]; | 
|  | 50 | +        long r = f[m] * f[l - m] % M; | 
|  | 51 | +        for (int d = 0; d <= 9; d++) { | 
|  | 52 | +            r = r * invF[c[d]] % M; | 
|  | 53 | +        } | 
|  | 54 | +        r = r * w % M; | 
|  | 55 | +        return (int) r; | 
| 74 | 56 |     } | 
| 75 | 57 | 
 | 
| 76 |  | -    private static long choose(int a, int b) { | 
| 77 |  | -        while (a >= LONGS.size()) { | 
| 78 |  | -            long[] prev = LONGS.get(LONGS.size() - 1); | 
| 79 |  | -            long[] next = new long[prev.length + 1]; | 
| 80 |  | -            for (int i = 0; i < prev.length; i++) { | 
| 81 |  | -                next[i] = (next[i] + prev[i]) % M; | 
| 82 |  | -                next[i + 1] = prev[i]; | 
|  | 58 | +    private long modInverse(long a, int m) { | 
|  | 59 | +        long r = 1; | 
|  | 60 | +        long p = m - 2; | 
|  | 61 | +        long b = a; | 
|  | 62 | +        while (p > 0) { | 
|  | 63 | +            if ((p & 1) == 1) { | 
|  | 64 | +                r = r * b % m; | 
| 83 | 65 |             } | 
| 84 |  | -            LONGS.add(next); | 
| 85 |  | -        } | 
| 86 |  | -        if (a - b < b) { | 
| 87 |  | -            b = a - b; | 
|  | 66 | +            b = b * b % m; | 
|  | 67 | +            p >>= 1; | 
| 88 | 68 |         } | 
| 89 |  | -        if (b < 0) { | 
|  | 69 | +        return r; | 
|  | 70 | +    } | 
|  | 71 | + | 
|  | 72 | +    private long comb(int n, int k, long[] f, long[] invF, int m) { | 
|  | 73 | +        if (k > n) { | 
| 90 | 74 |             return 0; | 
| 91 | 75 |         } | 
| 92 |  | -        return LONGS.get(a)[b]; | 
|  | 76 | +        return f[n] * invF[k] % m * invF[n - k] % m; | 
| 93 | 77 |     } | 
| 94 | 78 | } | 
0 commit comments