k-balance number
Difficulty: Hard

Your task is to calculate the sum (indicated by S) of all the k-balanced integers between [L, R]. An integer is called k-balanced when either of #1 or #2 below holds true.

1. The length of the integer <= k     
2. Sum of the first k digits (with no leading zeros) is equal to the sum of the last k digits.    

**Input format**  
L R k

**Output format**  
S % 1000000007

**Constraints**  
0 < L <= R < 10^18  
0 < k <= 18

**Sample Input**  
9 23 1

**Sample Output**  
42

**Explanation**  
9, 11 and 22 are the only 3 integers between 9 and 23 ( both included ) that are k-balanced. Hence, the answer is 9+11+22=42


Input Format:

Output Format:

Sample Input:

Sample Output:

Python 3 starter code:

Editorial: May 20-20 Hack Editorial: K-Balance
<style id="MathJax_SVG_styles">.MathJax_SVG_Display {text-align: center; margin: 1em 0em; position: relative; display: block!important; text-indent: 0; max-width: none; max-height: none; min-width: 0; min-height: 0; width: 100%}
.MathJax_SVG .MJX-monospace {font-family: monospace}
.MathJax_SVG .MJX-sans-serif {font-family: sans-serif}
.MathJax_SVG {display: inline; font-style: normal; font-weight: normal; line-height: normal; font-size: 100%; font-size-adjust: none; text-indent: 0; text-align: left; text-transform: none; letter-spacing: normal; word-spacing: normal; word-wrap: normal; white-space: nowrap; float: none; direction: ltr; max-width: none; max-height: none; min-width: 0; min-height: 0; border: 0; padding: 0; margin: 0}
.MathJax_SVG * {transition: none; -webkit-transition: none; -moz-transition: none; -ms-transition: none; -o-transition: none}
.mjx-svg-href {fill: blue; stroke: blue}
</style><svg style="display: none;"><defs id="MathJax_SVG_glyphs"></defs></svg><p><strong><a href="https://www.hackerrank.com/contests/may13/challenges/k-blance">K Balance</a></strong></p>

<p>Find the sum of numbers between L and R having either &lt;= K digits or having sum of first K digits equal to sum of last K digits.</p>

<p><strong>Difficulty Level</strong></p>

<p>Hard</p>

<p><strong>Problem Setter</strong></p>

<p><a href="https://www.hackerrank.com/wanbo">Wanbo</a> <br>
Editorial by <a href="https://www.hackerrank.com/piyush006">Piyush</a></p>

<p><strong>Required Knowledge</strong></p>

<p>Combinatorics, Dynamic Programming</p>

<p><strong>Approach</strong></p>

<p>Let's reduce the problem to finding </p>

<pre><code>f(n) = the sum of K-balance numbers &lt;= N
</code></pre>

<p>The answer to the problem will then be </p>

<pre><code>f(r) - f(l-1)



f(N){
    // D is the number of digits of N.
    D = Digits(N);
    ans = 0;
    //For numbers with lesser number of digits.
    for(I = 1; I &lt; |D|;I++) ans += f(I);
    //For numbers with equal number of digits.
    ans += Sum(); // what is sum?
}
</code></pre>

<p>We can reduce K if the first K digits overlap with last K digits, so that they don't overlap. 
To find Sum() , we can break our sum into sum at individual digit position and then sum it as : </p>

<pre><code>10^(d-1) * S(d-1) + 10^(d-2)*S(d-2) + .. 10^(0) * S(0) // S(i) is the sum of digits at position i
</code></pre>

<p>For finding sum at individual digit position i, we can again break it into as :</p>

<pre><code>0*Count(0) + 1*Count(1) + 2*Count(2) + ... + 9*Count(9) // Count(j) is the count of numbers having digit j at position i. 
</code></pre>

<p>So our approach looks like : </p>

<pre><code>Sum()
{
    ans = 0;
    for(I = 0;I &lt;= |D|;I++){
        SumAtI = 0;
        for(J=1;J&lt;=9;J++){
            SumAtI += J*Count(I , J);
        }
        ans += SumAtI * 10^(I);
    }
}
</code></pre>

<p>Finding Count(p , x) <br>
We have simply fixed the digit at some position 'p' to be 'x' , and we have to find the count of numbers which have digit at position 'p' as 'x'. There have to be |D| - p digits before p , and p - 1 after p that will form a number . Also sum of first K digits should be equal to last K . Another condition is that since the number of digits is equal to |D| , we need to take care of the fact that the number does not exceed N itself. For doing this , we take a function: F(I , State , Sum) . This means that we are at the Ith digit , and State tells us that if  all the digits taken before are equal to corresponding digits of N (if true would imply that Ith digit has to be &lt;= Ith digit of N) , Sum stores the sum of digits taken in the first K digits.We will increase sum if Ith digit is in first K digits , decrease if it is in the last K digits , and make no change if it is between .This way if we get 0 sum in the end , that means our number satisfies all conditions.</p>

<pre><code>F(I,state,sum){
    //Base Case
    if(N == -1) return (Sum == 0);
    //If Ith is first digit , we can't take 0 .
    //If state variable is true , that means we are in prefix of N , so Ith digit has to be less than Dig[I]
    for(J = ((I == |D| - 1) ? 1 : 0) ;J &lt;= (state ? Dig[I] : 9); J++){
        //digit is in first K digits.
        if(I &gt;= |D| - K)
            r += F(I - 1, state &amp;&amp; (Dig[I] == J) , sum + J);
        //digit is in last K digits.
        else if(n &lt; K){
            if(sum &gt;= i)
                ans += F(I - 1, state &amp;&amp; (Dig[I] == J), sum - J);
        }
        //digit is in between
        else ans += F(I - 1, state &amp;&amp; (Dig[I] == J), sum);        
    }
    return ans;
}
</code></pre>

<p>Returning to Count(p, x)
We only have the pth digit as x, but depending on starting |D|-p digits , we can have different values of (state,sum) at pth digit, so we will try all such values of (state,sum), and count the total numbers.</p>

<pre><code>Count(p, x){
    for(State = 0 ; State &lt;= 1; State ++){
        for(Sum = 0; Sum &lt;= (|D| - p)*9 ;Sum++){
            ans += [ Numbers With (|D|-p)_Digits And Reach (State,Sum) ] * [ F(p,state,sum) and x as the pth digit] ;
        }
    }
}
</code></pre>

<p>Finding the count of numbers with \|D\|-P digits and reaching (state,sum) as required can be done either using another recursive function , or using function F itself . This completes our Sum() function . Find(x) function is easy to implement as well if you have understood the basic idea developed above( would be good exercise infact) . It can be also be eliminated, but at the cost of one more variable in the state of function F.</p>

<p><strong>Problem Setter's Code: C++</strong></p>

<p><a href="https://gist.github.com/dheerajrav/5757729">Setter's code</a></p>

<p><strong>Problem Tester's Code: C++</strong></p>

<p><a href="https://www.hackerrank.com/rest/contests/may13/challenges/k-blance/hackers/piyush006/download_solution">Tester's code</a></p>

Reference solution (C++):
###C++  
```cpp  
#include<map>
#include<set>
#include<ctime>
#include<cmath>
#include<queue>
#include<stack>
#include<bitset>
#include<vector>
#include<cstdio>
#include<string>
#include<cassert>
#include<cstring>
#include<numeric>
#include<sstream>
#include<iterator>
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long LL;
#define MM(a,x) memset(a, x, sizeof(a))
#define P(x) cout<<#x<<" = "<<x<<endl;
#define P2(x,y) cout<<#x<<" = "<<x<<", "<<#y<<" = "<<y<<endl;
#define PV(a,n) for(int i=0;i<n;i++) cout<<#a<<"[" << i <<"] = "<<a[i]<<endl;
#define TM(a,b) cout<<#a<<"->"<<#b<<": "<<1.*(b-a)/CLOCKS_PER_SEC<<"s\n";

const LL MD = LL(1e9) + 7;

LL ten[51];
LL p10[51];
LL h(LL m);

LL brute(LL L, LL R, int k) {
    LL ret = 0;
    for(int i = L; i <= R; i++) {
        int s[100], ct;
        if(i % 100000000 == 0) P(i);
        LL T = i;
        ct = 0;
        while(T) {
            s[ct++] = T % 10;
            T /= 10;
        }
        if(ct < k) {ret += i; continue;}
        int sL = 0, sR = 0;
        for(int j = 0; j < k; j++) {
            sL += s[j];
            sR += s[ct - j - 1];
        }
        if(sL == sR)
            ret = (ret + i) % MD;
    }
    return ret % MD;
}

vector<int> toD(LL n) {
    vector<int> r;
    while(n) {
        r.push_back(n % 10);
        n /= 10;
    }
    reverse(r.begin(), r.end());
    return r;
}

LL h(LL m) {
    LL L = 1, R = LL(pow(10., (int)m) + 0.5) - 1;
    LL t1 = L + R;
    LL n = R - L + 1;
    if(t1 % 2 == 0) t1 /= 2;
    else if(n % 2 == 0) n /= 2;
    t1 %= MD;
    n %= MD;
    LL ret = t1 * n % MD;
    return ret;
}


LL g(int cur, int sz, int p[], int k, bool allZero) {
//    PV(p, sz);
//    P(cur);
    LL ret = 0;
    int pZero = 0;
    for(int i = 0; i < cur; i++) {
        if(p[i] == 0) {
            pZero = i + 1;
        } else {
            break;
        }
    }

    vector<int> d;
    for(int i = pZero; i < cur; i++) d.push_back(p[i]);
    sz -= pZero;

    int nsure = d.size(), L, R, M;

    if(sz <= k) {
        LL sure = 0;
        for(int i = 0; i < nsure; i++) {
            sure = (10 * sure + d[i]) % MD;
        }
        int nosure = sz - nsure;
        int minus = allZero && (nosure > 0);
        ret = (h(nosure) - minus * h(nosure - 1) % MD + (ten[nosure] - minus * ten[nosure - 1]) % MD * ten[nosure] % MD * sure % MD) % MD;
        if(ret < 0) ret += MD;
        return ret;
    }

    if(2 * k <= sz) {
        M = sz - 2 * k, L = R = k;
    } else {
        M = 2 * k - sz, L = R = sz - k;
    }

    LL dL[10][100] = {};
    LL X[10][100] = {};
    X[0][0] = 1;
    for(int i = 1; i <= 9; i++) {
        int st = (i == 1 && allZero) ? 1 : 0;
        for(int j = 0; j < 100; j++) {
            for(int l = st; l <= 9 && l <= j; l++) {
                X[i][j] += X[i - 1][j - l];
            }
            X[i][j] %= MD;
        }
    }

    LL dR[10][100] = {};
    LL Y[10][100] = {};
    Y[0][0] = 1;
    for(int i = 1; i <= 9; i++) {
        for(int j = 0; j < 100; j++) {
            for(int l = 0; l <= 9 && l <= j; l++) {
                Y[i][j] += Y[i - 1][j - l];
            }
            Y[i][j] %= MD;
        }
    }

    for(int i = 1; i <= 9; i++)
        for(int j = 0; j < 100; j++) {
            for(int x = i - 1; x >= 0; x--) {
                for(int y = (allZero && x == i - 1); y <= 9 && y <= j; y++) {
                    if(x != i - 1)
                        dL[i][j] += X[i - 1][j - y] * y % MD * ten[x] % MD;
                    else
                        dL[i][j] += Y[i - 1][j - y] * y % MD * ten[x] % MD;
                }
            }
            dL[i][j] %= MD;
        }
    for(int i = 1; i <= 9; i++)
        for(int j = 0; j < 100; j++) {
            for(int x = i - 1; x >= 0; x--) {
                for(int y = 0; y <= 9 && y <= j; y++) {
                    dR[i][j] += Y[i - 1][j - y] * y % MD * ten[x] % MD;
                }
            }
            dR[i][j] %= MD;
        }
    if(nsure < L) {
        //    cout << "1)" << endl;
        int nL = L - nsure;
        int sL = 0;
        LL sure = 0;
        for(int i = 0; i < nsure; i++) {
            sure = (10 * sure + d[i]) % MD;
            sL += d[i];
        }

        for(int ds = 0; ds + sL < 100; ds++) {
            LL cL = ten[M] * Y[R][ds + sL] % MD;
            LL vL = (dL[nL][ds] + X[nL][ds] * sure % MD * ten[nL]) % MD * ten[M + R] % MD;
            ret += cL * vL % MD;

            LL cM = X[nL][ds] * Y[R][ds + sL] % MD;
            LL vM = h(M) * ten[R] % MD;
            ret += cM * vM % MD;

            LL cR = X[nL][ds] * ten[M];
            LL vR = dR[R][ds + sL];
            ret += cR * vR % MD;
        }
        ret %= MD;
    } else if(nsure <= L + M) {
        //    cout << "2)" << endl;
        int sL = 0;
        int nM = L + M - nsure;
        LL vL = 0, vM = 0;
        for(int i = 0; i < L; i++) {
            sL += d[i];
            vL = (10 * vL + d[i]) % MD;
        }
        for(int i = L; i < nsure; i++) {
            vM = (10 * vM + d[i]) % MD;
        }

        LL cL = ten[nM] * Y[R][sL] % MD;
        vL = vL * ten[M + R] % MD;
        ret += cL * vL % MD;

        LL cM = Y[R][sL] % MD;
        vM = vM * ten[nM] % MD;
        vM = (h(nM) + vM * ten[nM]) % MD * ten[R] % MD;
        ret += cM * vM % MD;

        LL cR = ten[nM];
        LL vR = dR[R][sL];
        ret += cR * vR % MD;
        ret %= MD;
    } else {
        //    cout << "3)" << endl;
        LL sure = 0;
        int sL = 0, sR = 0;
        for(int i = 0; i < L; i++) sL += d[i];
        for(int i = L + M; i < nsure; i++) sR += d[i];
        for(int i = 0; i < nsure; i++) sure = (10 * sure + d[i]) % MD;

        int nR = R - (nsure - (L + M));
        if(sL >= sR) {
            LL cR = Y[nR][sL - sR];
            LL vR = dR[nR][sL - sR];
            ret += (vR + sure * ten[nR] % MD * cR) % MD;
            ret %= MD;
        }
    }
    //P(ret);
    //cout << endl;
    return ret;
}

void dfs(int cur, vector<int>& D, int p[], int k, bool isEqual, bool allZero, LL & r) {
    int sz = (int) D.size();
    if(cur == sz) {
        if(isEqual)    return;
        else r += g(cur, D.size(), p, k, allZero);
        return;
    }
    if(isEqual) {
        for(int i = 0; i <= D[cur]; i++) {
            p[cur] = i;
            dfs(cur + 1, D, p, k, i == D[cur], allZero && (i == 0), r);
        }
    } else {
        if(allZero) {
            for(int i = cur; i < D.size(); i++) {
                r += g(i, D.size(), p, k, 1);
                p[i] = 0;
            }
        } else {
            r += g(cur, D.size(), p, k, 0);
        }
    }
}

//1,2,...,n
LL f(LL n, LL k) {
    vector<int> D = toD(n);
    LL r = 0;
    int p[50] = {};
    dfs(0, D, p, k, 1, 1, r);
    r %= MD;
    return r;
}

int main() {
    p10[0] = ten[0] = 1;
    for(int i = 1; i < 50; i++) {
        p10[i] = 10 * p10[i - 1];
        ten[i] = 10 * ten[i - 1] % MD;
    }
    LL L, R, k;
    cin >> L >> R >> k;
    assert(L <= R && R < LL(1e18));
    LL rL = f(L, k);
    LL rR = f(R + 1, k);
//    P(rL);
//    P(rR);
    LL r = (rR - rL + MD) % MD;
    cout << r << endl;
    //P(brute(L, R, k));
    return 0;
}
```