Challenge: Digit Products

Subdomeniu: Combinatorics (combinatorics)

Scor cont: 60.0 / 60

Submission status: Accepted

Submission score: 1.0

Submission ID: 464756451

Limbaj: cpp14

Link challenge: https://www.hackerrank.com/challenges/digit-products/problem

Cerinta

Let $D(X)$ be a function that calculates the digit product of $X$ in base $10$ without leading zeros. For instance:

$D(0) = 0$  
$D(234) = 2 \times 3 \times 4 = 24$  
$D(104) = 1 \times 0 \times 4 = 0$  

You are given three positive integers $A, B$ and $K$. Determine how many integers exist in the range $[A, B]$ whose digit product equals $K$. Formally speaking, you are required to count the number of distinct integer solutions of $X$ where $A \leqslant X \leqslant B$ and $D(X) = K$.

Input Format

The first line contains $T$, the number of test cases. <br>
The next $T$ lines each contain three positive integers: $A$, $B$ and $K$, respectively.

**Constraints**  
$T \leqslant 10000$  
$1 \leqslant A \leqslant B \leqslant 10^{100}$  
$1 \leqslant K \leqslant 10^{18}$

Output Format

For each test case, print the following line:

*Case* $X$$: Y$

$X$ is the test case number, starting at $1$.  
$Y$ is the number of integers in the interval $[A, B]$ whose digit product is equal to $K$. 

Because $Y$ can be a huge number, print it modulo $(10^9 + 7)$.

Cod sursa

#include <bits/stdc++.h>
using namespace std;

static const int MOD = 1000000007;
static const int MAXLEN = 100;

struct State {
    uint8_t a, b, c, d;
};

static inline uint32_t packExp(int a, int b, int c, int d) {
    return (uint32_t)a | ((uint32_t)b << 6) | ((uint32_t)c << 12) | ((uint32_t)d << 18);
}

string decOne(string s) {
    if (s == "0") return "0";
    int i = (int)s.size() - 1;
    while (i >= 0 && s[i] == '0') {
        s[i] = '9';
        --i;
    }
    if (i >= 0) s[i]--;
    int p = 0;
    while (p + 1 < (int)s.size() && s[p] == '0') ++p;
    s.erase(0, p);
    if (s.empty()) return "0";
    return s;
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    // 1) Build all exponent states (a,b,c,d) with 2^a 3^b 5^c 7^d <= 1e18.
    const unsigned long long LIM = 1000000000000000000ULL;

    vector<State> states;
    states.reserve(70000);
    unordered_map<uint32_t, int> id;
    id.reserve(140000);

    for (int a = 0;; ++a) {
        __int128 v2 = 1;
        for (int i = 0; i < a; ++i) {
            v2 *= 2;
            if (v2 > LIM) break;
        }
        if (v2 > LIM) break;

        for (int b = 0;; ++b) {
            __int128 v23 = v2;
            for (int i = 0; i < b; ++i) {
                v23 *= 3;
                if (v23 > LIM) break;
            }
            if (v23 > LIM) break;

            for (int c = 0;; ++c) {
                __int128 v235 = v23;
                for (int i = 0; i < c; ++i) {
                    v235 *= 5;
                    if (v235 > LIM) break;
                }
                if (v235 > LIM) break;

                __int128 cur = v235;
                for (int d = 0;; ++d) {
                    if (cur > LIM) break;
                    uint32_t key = packExp(a, b, c, d);
                    int idx = (int)states.size();
                    states.push_back(State{(uint8_t)a, (uint8_t)b, (uint8_t)c, (uint8_t)d});
                    id[key] = idx;
                    cur *= 7;
                }
            }
        }
    }

    int S = (int)states.size();
    int idOne = id[packExp(0, 0, 0, 0)];

    // 2) Precompute backward transitions by placing one digit in {1..9}.
    int da[10] = {0, 0, 1, 0, 2, 0, 1, 0, 3, 0};
    int db[10] = {0, 0, 0, 1, 0, 0, 1, 0, 0, 2};
    int dc[10] = {0, 0, 0, 0, 0, 1, 0, 0, 0, 0};
    int dd[10] = {0, 0, 0, 0, 0, 0, 0, 1, 0, 0};

    vector<array<int, 10>> prevState(S);
    for (int i = 0; i < S; ++i) {
        for (int d = 1; d <= 9; ++d) prevState[i][d] = -1;
        auto st = states[i];
        for (int d = 1; d <= 9; ++d) {
            if (st.a < da[d] || st.b < db[d] || st.c < dc[d] || st.d < dd[d]) continue;
            uint32_t key = packExp(st.a - da[d], st.b - db[d], st.c - dc[d], st.d - dd[d]);
            auto it = id.find(key);
            if (it != id.end()) prevState[i][d] = it->second;
        }
    }

    // 3) DP[len][state] = number of len-digit strings over {1..9} with product exponents=state.
    vector<vector<int>> dp(MAXLEN + 1, vector<int>(S, 0));
    dp[0][idOne] = 1;

    for (int len = 1; len <= MAXLEN; ++len) {
        auto &cur = dp[len];
        auto &prv = dp[len - 1];
        for (int s = 0; s < S; ++s) {
            long long ways = 0;
            for (int dig = 1; dig <= 9; ++dig) {
                int ps = prevState[s][dig];
                if (ps >= 0) {
                    ways += prv[ps];
                    if (ways >= (long long)MOD * MOD) ways %= MOD;
                }
            }
            cur[s] = (int)(ways % MOD);
        }
    }

    auto countLE = [&](const string &X, int targetState) -> int {
        if (X == "0") return 0;

        int n = (int)X.size();
        long long ans = 0;

        // Shorter lengths.
        for (int len = 1; len < n; ++len) {
            ans += dp[len][targetState];
            if (ans >= MOD) ans -= MOD;
        }

        // Same length with prefix restriction.
        int remState = targetState;
        bool alive = true;

        for (int i = 0; i < n && alive; ++i) {
            int lim = X[i] - '0';
            int from = (i == 0 ? 1 : 0);

            for (int dig = from; dig < lim; ++dig) {
                if (dig == 0) continue; // product would be 0, impossible for K>=1
                int ps = prevState[remState][dig];
                if (ps >= 0) {
                    ans += dp[n - i - 1][ps];
                    ans %= MOD;
                }
            }

            if (lim == 0) {
                alive = false;
                break;
            }
            int ns = prevState[remState][lim];
            if (ns < 0) {
                alive = false;
                break;
            }
            remState = ns;
        }

        if (alive && remState == idOne) {
            ans++;
            if (ans >= MOD) ans -= MOD;
        }

        return (int)ans;
    };

    auto factorState = [&](unsigned long long K) -> int {
        int a = 0, b = 0, c = 0, d = 0;
        while (K % 2ULL == 0ULL) { K /= 2ULL; ++a; }
        while (K % 3ULL == 0ULL) { K /= 3ULL; ++b; }
        while (K % 5ULL == 0ULL) { K /= 5ULL; ++c; }
        while (K % 7ULL == 0ULL) { K /= 7ULL; ++d; }
        if (K != 1ULL) return -1;
        uint32_t key = packExp(a, b, c, d);
        auto it = id.find(key);
        if (it == id.end()) return -1;
        return it->second;
    };

    int T;
    cin >> T;
    for (int tc = 1; tc <= T; ++tc) {
        string A, B;
        unsigned long long K;
        cin >> A >> B >> K;

        int st = factorState(K);
        int ans = 0;
        if (st != -1) {
            int right = countLE(B, st);
            string A1 = decOne(A);
            int left = countLE(A1, st);
            ans = right - left;
            if (ans < 0) ans += MOD;
        }

        cout << "Case " << tc << ": " << ans << '\n';
    }

    return 0;
}
HackerRank Combinatorics – Digit Products