|
| 1 | +import 'dart:math'; |
| 2 | + |
| 3 | +class DigitCounter { |
| 4 | + Map<String, BigInt> memo = {}; |
| 5 | + late String numStr; |
| 6 | + late int digitLimit; |
| 7 | + |
| 8 | + BigInt dp(int index, bool tight, bool isLeadingZero) { |
| 9 | + if (index == numStr.length) { |
| 10 | + return BigInt.one; |
| 11 | + } |
| 12 | + String key = "$index-$tight-$isLeadingZero"; |
| 13 | + if (memo.containsKey(key)) { |
| 14 | + return memo[key]!; |
| 15 | + } |
| 16 | + |
| 17 | + BigInt ans = BigInt.zero; |
| 18 | + int currentDigitLimit = tight ? int.parse(numStr[index]) : 9; |
| 19 | + int upperBound = min(currentDigitLimit, digitLimit); |
| 20 | + |
| 21 | + for (int digit = 0; digit <= upperBound; digit++) { |
| 22 | + bool newTight = tight && (digit == currentDigitLimit); |
| 23 | + ans += dp(index + 1, newTight, isLeadingZero && (digit == 0)); |
| 24 | + } |
| 25 | + |
| 26 | + memo[key] = ans; |
| 27 | + return ans; |
| 28 | + } |
| 29 | + |
| 30 | + BigInt count(BigInt n, int limit) { |
| 31 | + if (n < BigInt.zero) { |
| 32 | + return BigInt.zero; |
| 33 | + } |
| 34 | + numStr = n.toString(); |
| 35 | + digitLimit = limit; |
| 36 | + memo.clear(); // new count. |
| 37 | + return dp(0, true, true); |
| 38 | + } |
| 39 | +} |
| 40 | + |
| 41 | +BigInt countUpTo(BigInt n, int limit) { |
| 42 | + return DigitCounter().count(n, limit); |
| 43 | +} |
| 44 | + |
| 45 | +BigInt solve(BigInt n, int limit, String s) { |
| 46 | + for (int i = 0; i < s.length; i++) { |
| 47 | + if (int.parse(s[i]) > limit) { |
| 48 | + return BigInt.zero; |
| 49 | + } |
| 50 | + } |
| 51 | + |
| 52 | + BigInt sValue = BigInt.parse(s); |
| 53 | + if (n < sValue) { |
| 54 | + return BigInt.zero; |
| 55 | + } |
| 56 | + |
| 57 | + BigInt power = BigInt.from(10).pow(s.length); |
| 58 | + // count of 'y' such that x = y * 10^L + s <= n. |
| 59 | + BigInt nPrime = (n - sValue) ~/ power; |
| 60 | + |
| 61 | + return countUpTo(nPrime, limit); |
| 62 | +} |
| 63 | + |
| 64 | +int countPowerfulIntegers(int start, int finish, int limit, String s) { |
| 65 | + BigInt finishBig = BigInt.from(finish); |
| 66 | + BigInt startMinusOneBig = BigInt.from(start) - BigInt.one; |
| 67 | + |
| 68 | + BigInt countFinish = solve(finishBig, limit, s); |
| 69 | + BigInt countStart = solve(startMinusOneBig, limit, s); |
| 70 | + |
| 71 | + BigInt result = countFinish - countStart; |
| 72 | + return result.toInt(); |
| 73 | +} |
| 74 | + |
| 75 | +void main() { |
| 76 | + // Example 1 |
| 77 | + int start1 = 1; |
| 78 | + int finish1 = 6000; |
| 79 | + int limit1 = 4; |
| 80 | + String s1 = "124"; |
| 81 | + print("Expected: 5"); |
| 82 | + print("Output: ${countPowerfulIntegers(start1, finish1, limit1, s1)}"); |
| 83 | + |
| 84 | + // Example 2 |
| 85 | + int start2 = 15; |
| 86 | + int finish2 = 215; |
| 87 | + int limit2 = 6; |
| 88 | + String s2 = "10"; |
| 89 | + print("Expected: 2"); |
| 90 | + print("Output: ${countPowerfulIntegers(start2, finish2, limit2, s2)}"); |
| 91 | +} |
0 commit comments