Challenge: Binomial Coefficients Revenge

Subdomeniu: Combinatorics (combinatorics)

Scor cont: 100.0 / 100

Submission status: Accepted

Submission score: 1.0

Submission ID: 464764349

Limbaj: cpp14

Link challenge: https://www.hackerrank.com/challenges/bincoefrevenge/problem

Cerinta

The binomial coefficient _C(N, K)_ is defined as
_N! / K! / (N − K)!_ for _0 ≤ K ≤ N_.  
Here _N! = 1 \* 2 \* ... \* N_ for _N ≥ 1_, and _0! = 1_.

You are given a prime number _P_ and a positive integer _N_. 

_A<sub>L</sub>_ is defined as the number of elements in the sequence _C(N, K)_, such that, _P<sup>L</sup>_ divides _C(N, K)_,
but _P<sup>L+1</sup>_ does not divide _C(N, K)_. Here, _0 ≤ K ≤ N_.


Let _M_ be an integer, such that, _A<sub>M</sub> > 0_,
but _A<sub>L</sub> = 0_ for all _L > M_.
Your task is to find numbers _A<sub>0</sub>, A<sub>1</sub>, ..., A<sub>M</sub>_.

**Input Format**  
The first line of the input contains an integer _T_, denoting the number of test cases.
The description of _T_ test cases follows.
The only line of each test case contains two space-separated integers _N_ and _P_.

**Output Format**  
For each test case, display _M + 1_ space separated integers
_A<sub>0</sub>, A<sub>1</sub>, ..., A<sub>M</sub>_
on the separate line.

**Constraints**

1 ≤ T ≤ 100  
1 ≤ N ≤ 10<sup>18</sup>  
2 ≤ P < 10<sup>18</sup>  
P is prime  


**Sample Input**

    3
    4 5
    6 3
    10 2

**Sample Output**

    5
    3 4
    4 4 1 2


**Explanation**  

**Example case 1.** Values _C(4, K)_ are _{1, 4, 6, 4, 1}_.
Each of them is not divisible by 5.
Therefore, _A<sub>0</sub> = 5_, _A<sub>1</sub> = 0_, _A<sub>2</sub> = 0_, ..., hence the answer.


**Example case 2.** Values _C(6, K)_ are _{1, 6, 15, 20, 15, 6, 1}_.
Among them _1, 20, 1_ are not divisible by _3_,
while remaining values _6, 15, 15, 6_ are divisible by _3_, but not divisible by _9_.
Therefore, _A<sub>0</sub> = 3_, _A<sub>1</sub> = 4_,
_A<sub>2</sub> = 0_, _A<sub>3</sub> = 0_, ..., hence the answer.


**Example case 3.** Values _C(10, K)_ are _{1, 10, 45, 120, 210, 252, 210, 120, 45, 10, 1}_.
Among them _1, 45, 45, 1_ are not divisible by _2_,
values _10, 210, 210, 10_ are divisible by _2_, but not divisible by _4_,
value _252_ is divisible by _4_, but not divisible by _8_,
finally, values _120, 120_ are divisible by _8_, but not divisible by _16_.
Therefore, _A<sub>0</sub> = 4_, _A<sub>1</sub> = 4_,
_A<sub>2</sub> = 1_, _A<sub>3</sub> = 2_,
_A<sub>4</sub> = 0_, _A<sub>5</sub> = 0_, ..., hence the answer.

Cod sursa

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

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

    int T;
    cin >> T;
    while (T--) {
        unsigned long long N, P;
        cin >> N >> P;

        vector<unsigned long long> dig;
        if (N == 0) {
            dig.push_back(0);
        } else {
            while (N > 0) {
                dig.push_back(N % P);
                N /= P;
            }
        }

        int d = (int)dig.size();
        vector<unsigned long long> dp0(d + 1, 0), dp1(d + 1, 0);
        dp0[0] = 1; // no digits processed, borrow=0

        for (int i = 0; i < d; ++i) {
            vector<unsigned long long> ndp0(d + 1, 0), ndp1(d + 1, 0);
            unsigned long long ni = dig[i];

            for (int c = 0; c <= i; ++c) {
                // from borrow = 0
                if (dp0[c]) {
                    unsigned long long ways_nb0 = ni + 1;   // k_i <= ni
                    unsigned long long ways_nb1 = P - ways_nb0;

                    ndp0[c] += (unsigned long long)((__int128)dp0[c] * ways_nb0);
                    if (ways_nb1) ndp1[c + 1] += (unsigned long long)((__int128)dp0[c] * ways_nb1);
                }

                // from borrow = 1
                if (dp1[c]) {
                    unsigned long long ways_nb0 = ni;       // k_i <= ni-1
                    unsigned long long ways_nb1 = P - ways_nb0;

                    if (ways_nb0) ndp0[c] += (unsigned long long)((__int128)dp1[c] * ways_nb0);
                    ndp1[c + 1] += (unsigned long long)((__int128)dp1[c] * ways_nb1);
                }
            }

            dp0.swap(ndp0);
            dp1.swap(ndp1);
        }

        vector<unsigned long long> A(d + 1, 0);
        for (int c = 0; c <= d; ++c) A[c] = dp0[c]; // final borrow must be 0

        int M = d;
        while (M > 0 && A[M] == 0) --M;

        for (int i = 0; i <= M; ++i) {
            if (i) cout << ' ';
            cout << A[i];
        }
        cout << '\n';
    }

    return 0;
}
HackerRank Combinatorics – Binomial Coefficients Revenge