Challenge: Irresponsible Numbers

Subdomeniu: Combinatorics (combinatorics)

Scor cont: 75.0 / 75

Submission status: Accepted

Submission score: 1.0

Submission ID: 464763594

Limbaj: cpp14

Link challenge: https://www.hackerrank.com/challenges/irresponsible-numbers/problem

Cerinta

A number, $x$, is called *irresponsible* when adding $x$ to $x+1$ requires a *[carry](https://en.wikipedia.org/wiki/Carry_(arithmetic))* operation. For example, $5$, $17$, and $91$ are irresponsible numbers because adding them to $6$, $18$, and $92$ (respectively) requires a carry operation:

- In $5 + (5 + 1) = 5 + 6 = 11$, a $1$ is carried over into the $10$'s place. 
- In $17 + (17 + 1) = 17 + 18 = 35$, a $2$ is carried over into the $10$'s place.
- In $91 + (91 + 1) = 91 + 92 = 183$, a $1$ is carried over into the $100$'s place.

You have two integers, $x$ and $n$. Construct a new number, $s$, by repeating $x$ a total of $n$ times. For example, if $x = 3121$ and $n = 4$, then $s = 3121312131213121$.

Given $x$ and $n$, construct $s$ and find all the irreponsible numbers between $1$ and $s$. Then print the number of irresponsible numbers in the aforementioned range; as this number can be quite large, your answer must be modulo $10^9+7$.

Input Format

A single line with two space-separated integers denoting the respective values of $x$ and $n$.

Output Format

Print a single integer denoting the number of irresponsible numbers between $1$ and $s$, modulo $10^9+7$.

Constraints

* $1 \leq x \leq 10^{1,000,000}$
* $1 \leq n \leq 10^{18}$

**Subtasks**

For $15\%$ of the maximum score: 

* $1 \leq x \leq 10^6$
* $n = 1$

For $40\%$ of the maximum score: 

* $1 \leq x \leq 10^{1,000,000}$
* $n = 1$

Cod sursa

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

static const long long MOD = 1000000007LL;

struct Mat {
    long long a[4][4];
    Mat(bool ident = false) {
        for (int i = 0; i < 4; ++i)
            for (int j = 0; j < 4; ++j)
                a[i][j] = (ident && i == j) ? 1 : 0;
    }
};

long long modpow(long long x, long long e) {
    long long r = 1 % MOD;
    x %= MOD;
    if (x < 0) x += MOD;
    while (e > 0) {
        if (e & 1LL) r = (__int128)r * x % MOD;
        x = (__int128)x * x % MOD;
        e >>= 1LL;
    }
    return r;
}

Mat mul(const Mat &A, const Mat &B) {
    Mat C;
    for (int i = 0; i < 4; ++i) {
        for (int k = 0; k < 4; ++k) if (A.a[i][k]) {
            long long aik = A.a[i][k];
            for (int j = 0; j < 4; ++j) if (B.a[k][j]) {
                C.a[i][j] = (C.a[i][j] + (__int128)aik * B.a[k][j]) % MOD;
            }
        }
    }
    return C;
}

array<long long,4> mulVec(const Mat &A, const array<long long,4> &v) {
    array<long long,4> r{0,0,0,0};
    for (int i = 0; i < 4; ++i) {
        long long s = 0;
        for (int j = 0; j < 4; ++j) {
            s = (s + (__int128)A.a[i][j] * v[j]) % MOD;
        }
        r[i] = s;
    }
    return r;
}

Mat mpow(Mat base, long long exp) {
    Mat res(true);
    while (exp > 0) {
        if (exp & 1LL) res = mul(base, res);
        base = mul(base, base);
        exp >>= 1LL;
    }
    return res;
}

Mat transDigit(int c) {
    Mat T;
    int alpha = (c <= 4) ? 1 : 0;
    int beta = (c == 9) ? 1 : 0;
    int lessA = min(c, 5);

    // state order: EA, EB, LA, LB
    // EA' = alpha*EA
    T.a[0][0] = alpha;

    // EB' = beta*EA + beta*EB
    T.a[1][0] = beta;
    T.a[1][1] = beta;

    // LA' = lessA*EA + 5*LA
    T.a[2][0] = lessA;
    T.a[2][2] = 5;

    // LB' = LA + LB
    T.a[3][2] = 1;
    T.a[3][3] = 1;

    return T;
}

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

    string xs;
    long long n;
    cin >> xs >> n;

    // Block transition for one copy of x
    Mat block(true);
    for (char ch : xs) {
        int d = ch - '0';
        Mat Td = transDigit(d);
        block = mul(Td, block);
    }

    Mat all = mpow(block, n);

    array<long long,4> v0{1,0,0,0}; // equal + in prefix-state
    auto vf = mulVec(all, v0);

    long long responsible_0_to_S = (vf[0] + vf[1] + vf[2] + vf[3]) % MOD;
    long long responsible_pos = (responsible_0_to_S - 1 + MOD) % MOD; // exclude 0

    // S = x repeated n times, modulo MOD
    long long xv = 0;
    for (char ch : xs) xv = (xv * 10 + (ch - '0')) % MOD;
    long long p10L = modpow(10, (long long)xs.size());
    long long geom;
    if (p10L == 1) {
        geom = n % MOD;
    } else {
        long long num = (modpow(p10L, n) - 1 + MOD) % MOD;
        long long denInv = modpow((p10L - 1 + MOD) % MOD, MOD - 2);
        geom = (__int128)num * denInv % MOD;
    }
    long long Smod = (__int128)xv * geom % MOD;

    long long ans = (Smod - responsible_pos) % MOD;
    if (ans < 0) ans += MOD;
    cout << ans << '\n';
    return 0;
}
HackerRank Combinatorics – Irresponsible Numbers