Challenge: Binomial Coefficients

Subdomeniu: Number Theory (number-theory)

Scor cont: 60.0 / 60

Submission status: Accepted

Submission score: 1.0

Submission ID: 464733976

Limbaj: java8

Link challenge: https://www.hackerrank.com/challenges/binomial-coefficients/problem

Cerinta

In mathematics, **binomial coefficients** are a family of positive integers that occur as coefficients in the binomial theorem.  
$$n\choose k$$
denotes the number of ways of choosing k objects from n different objects.

However when n and k are too large, we often save them after modulo operation by a prime number P. Please calculate how many binomial coefficients of n become to 0 after modulo by P.

**Input Format**  
The first of input is an integer $T$, the number of test cases.  
Each of the following $T$ lines contains 2 integers, $n$ and prime $P$.  

**Constraints**  
$T < 100$  
$n < 10^{500}$  
$P < 10^9$

**Output Format**

For each test case, output a line contains the number of   $n \choose k$s (0<=k<=n)  each of which after modulo operation by P is 0.

**Sample Input**

    3
    2 2
    3 2
    4 3

**Sample Output**

    1
    0
    1

Cod sursa

//https://www.hackerrank.com/challenges/binomial-coefficients
//See: http://www.math.hmc.edu/funfacts/ffiles/30002.4-5.shtml

/*

//Updated version using BigInteger

import java.io.*;
import java.math.*;

public class Solution{
    
    public static void main(String[] args) throws IOException {
        StringBuffer sb = new StringBuffer();
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        
        for(byte T = Byte.parseByte(br.readLine()); T > 0; --T){
            String[] temp = br.readLine().split(" ");
            BigInteger N = new BigInteger(temp[0]);
            BigInteger P = new BigInteger(temp[1]);
            
            BigInteger R = BigInteger.ONE;
            BigInteger NP1 = N.add(BigInteger.ONE);
            while (N.compareTo(P) >= 0){
                BigInteger[] ar = N.divideAndRemainder(P);
                BigInteger quotient = ar[0];
                BigInteger remainder = ar[1];
                R = R.multiply(remainder.add(BigInteger.ONE));
                N = quotient;
            }
            R = R.multiply(N.add(BigInteger.ONE));
            R = NP1.subtract(R);
            
            sb.append(R + "\n");
        }
        
        System.out.print(sb);
    }
}

*/

//Original version using custom Number class

import java.io.*;

public class Solution{
    
    public static void main(String[] args) throws IOException {
        StringBuffer sb = new StringBuffer();
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        for(byte T = Byte.parseByte(br.readLine()); T > 0; --T){
            String[] temp = br.readLine().split(" ");
            int P = Integer.parseInt(temp[1]);
            Number N = new Number(temp[0], 10);
            Number NbP = N.clone();
            NbP.base(P);
            NbP.base(NbP.base()+1, false);
            NbP.addeq(new Number(array(NbP.digits(), 1), NbP.base()));
            Number X = NbP.multiplyDigits();
            N.addeq(new Number(1));
            N.subeq(X);
            sb.append(N + "\n");
        }
        System.out.print(sb);
    }
    
    private static int[] array(int length, int val){
        int[] ar = new int[length];
        while (length-- > 0){
            ar[length] = val;
        }
        return ar;
    }
    
    public static class Number{
        private int base;
        private int[] num; //Little endian
        private int digits;
        
        //Only supports strings up to base 10
        public Number(String str, int base){
            this(strToIntArr(str), base);
        }

        public Number(int num){
            this(num, 10);
        }
        
        //Supports any int base
        public Number(int num, int base){
            this(intToIntArr(num, base), base);
        }
        
        //Supports any int base
        public Number(int[] num, int base){
            this.num = num;
            this.base = base;
            this.digits = this.num.length;
            subDigits();
        }
        
        ////////////////////////
        //        DIGITS      //
        ////////////////////////
        
        public int digits(){
            return this.digits;
        }
        
        private void subDigits(){
            while (this.digits > 0 && this.num[this.digits - 1] < 1){
                this.digits--;
            }
        }
        
        private void addDigits(){
            while (this.digits < this.num.length && this.num[this.digits] > 0){
                this.digits++;
            }
        }
        
        ////////////////////////
        //        BASE        //
        ////////////////////////
        
        public int base(){
            return this.base;
        }
        
        public void base(int B){
            base(B, true);
        }
        
        public void base(int B, boolean convert){
            if (convert){
                int i;
                int[] N = this.num;
                int X = this.digits;
                int A = this.base;
                int Y = (int)(1.0d + X * Math.log(A) / Math.log(B));
                int[] ar = new int[Y];
                for(i = 0; i < Y && X > 0; ++i){
                    ar[i] = Number.diveq(N, X, A, B);
                    while (X > 0 && N[X-1] < 1){
                        --X;
                    }
                }
                this.num = ar;
                this.digits = i;
            }
            this.base = B;
        }
        
        ////////////////////////
        //         DIV        //
        ////////////////////////
        
        /*
        public int diveq(Number N){
        }
        */
        
        private static int diveq(int[] dividend, int length, int base, int divisor){
            long remainder = 0L;
            while(length-- > 0){
                remainder = remainder*base + dividend[length];
                dividend[length] = (int)(remainder/divisor);
                remainder %= divisor;
            }
            return (int)remainder;
        }
        
        ////////////////////////
        //         SUB        //
        ////////////////////////
        
        //Only works if difference is >= 0
        public void subeq(Number N){
            if (N.base != this.base){
                N = N.clone();
                N.base(this.base);
            }
            Number.subeq(this.num, this.digits, N.num, N.digits, this.base);
            subDigits();
        }
        
        //Only works if minuend >= subtrahend
        private static void subeq(int[] minuend, int mLength, int[] subtrahend, int sLength, int base){
            byte borrow = 0;

            //Subtract common indices
            for(int i = 0; i < sLength; ++i){
                minuend[i] -= subtrahend[i] + borrow;
                borrow = 0;
                if (minuend[i] < 0){
                    borrow = 1;
                    minuend[i] += base;
                }
            }

            //Subtract the remainding borrows
            if (borrow > 0){
                int i = sLength;
                int afterBorrow = base-1;
                while (i < mLength && minuend[i] == 0){
                    minuend[i++] = afterBorrow;
                }
                minuend[i] -= 1;
            }
        }
        
        ////////////////////////
        //         ADD        //
        ////////////////////////
        
        public void addeq(Number N){
            //Switch N to same base
            if (N.base != this.base){
                N = N.clone();
                N.base(this.base);
            }
            //Get max size of array needed
            int length = this.digits > N.digits ? this.digits + 1 : N.digits + 1;
            //Copy over current array to new array if needed
            this.num = this.num.length < length ? Number.arrayCopy(this.num, new int[length], 0, this.digits) : this.num;
            //Add
            Number.addeq(this.num, this.digits, N.num, N.digits, this.base);
            //Check for added digits
            addDigits();
        }
        
        private static void addeq(int[] adduend, int aLength, int[] addend, int bLength, int base){
            byte carry = 0;
            
            //Add together common indices
            for(int i = 0; i < bLength; ++i){
                adduend[i] += addend[i] + carry;
                carry = 0;
                if (adduend[i] >= base){
                    carry = 1;
                    adduend[i] -= base;
                }
            }
            
            //Add the remainding carries
            if (carry > 0){
                int i = bLength;
                int needsCarry = base-1;
                while(i < aLength && adduend[i] == needsCarry){
                    adduend[i++] = 0;
                }
                adduend[i] += 1;
            }
        }
        
        ////////////////////////
        //        MULT        //
        ////////////////////////
        
        public void multeq(Number multiplier){
            //Switch multiplier to same base
            if (multiplier.base != this.base){
                multiplier = multiplier.clone();
                multiplier.base(this.base);
            }
            //Create new array to fit product
            int[] product = new int[this.digits + multiplier.digits];
            //Multiply
            Number.multeq(this.num, this.digits, multiplier.num, multiplier.digits, product, product.length, this.base);
            this.num = product;
            //Check for added digits
            this.digits = product.length;
            subDigits();
        }
        
        private static void multeq(int[] multiplicand, int aLen, int[] multiplier, int bLen, int[] product, int cLen, int base){
            //For each digit of multiplier
            for(int i = 0; i < bLen; ++i){
                int j;
                int carry = 0;
                
                //Multiply multiplicand by digit
                for(j = 0; j < aLen; ++j){
                    long prod = (((long)multiplier[i]) * multiplicand[j]) + product[i+j] + carry;
                    carry = 0;
                    if (prod >= base){
                        carry = (int)(prod/base);
                        prod %= base;
                    }
                    product[i+j] = (int)prod;
                }
                
                //Add the remainding carry
                product[i+j] = carry;
            }
        }
        
        ////////////////////////
        //        OTHER       //
        ////////////////////////
        
        public Number multiplyDigits(){
            Number N = new Number("1", 10);
            
            for(int i = 0; i < this.digits; ++i){
                N.multeq(new Number(this.num[i]));
            }
            
            return N;
        }
        
        ////////////////////////
        //       HELPERS      //
        ////////////////////////
        
        private static int[] intToIntArr(int num, int base){
            int i;
            int A = 10;
            int Y = (int)(1.0d + Math.log(num)*Math.log(A)/Math.log(base));
            int[] ar = new int[Y];
            for(i = 0; i < Y && num > 0; ++i){
                ar[i] = num % base;
                num /= base;
            }
            return ar;
        }
        
        //Only supports strings up to base 10
        private static int[] strToIntArr(String str){
            int n = str.length();
            int[] ar = new int[n];
            for(char c : str.toCharArray()){
                ar[--n] = c - '0';
            }
            return ar;
        }
        
        public void shrink(){
            if (this.num.length > this.digits){
                this.num = Number.arrayCopy(this.num, this.digits);
            }
        }
        
        public int[] toArray(){
            return Number.arrayCopy(this.num, this.digits);
        }
        
        public Number clone(){
            return new Number(Number.arrayCopy(this.num, this.digits), this.base);
        }
        
        public String toString(){
            StringBuffer sb = new StringBuffer();
            int length = this.digits;
            if (length < 1){
                return "0";
            }
            while (length-- > 0){
                sb.append(this.num[length]);
            }
            return sb.toString();
        }
        
        private static int[] arrayCopy(int[] N, int length){
            return Number.arrayCopy(N, new int[length], 0, length);
        }
        
        private static int[] arrayCopy(int[] N, int[] ar, int min, int max){
            while(max-- > min){
                ar[max] = N[max];
            }
            return ar;
        }
    }
}
HackerRank Number Theory – Binomial Coefficients