Wednesday, June 25, 2014

SPOJ Problem GOODB


Good Predictions

Explanation:

This problem requires a simple implementation of nCr, some knowledge of modular multiplicative inverse (you can read here in detail) and some modular multiplication (you can find details here). Solution to the problem is explained below.

We are given, N, W, T and R, where W+T+R=N.


Now, out of N submissions, W submissions are wrong, and thus, no. of ways to choose W submissions out of N submissions will be given by, NCW.

After this, we are left with (N-W) submissions, and no. of ways to choose T submissions out of (N-W) submissions will be given by, (N-W)CT.
And finally, only (N-W-T) submissions are left, and no. of ways to choose R submissions out of (N-W-T) submissions will be given by, (N-W-T)CR.
And finally, we can multiply three results and modulo it with the number 10^9 + 7 and that will be the result.

Pretty easy, huh.

Now, comes the challenge. As we try to find the nCr for large numbers, we find that the result overflows. So, to get the results in the given range, we try to find (nCr) % (10^9 + 7), as explained below.

nCr = n! / (r! * (n-r)!)

                                               n * (n-1) * (n-2) * ... * 3 * 2 * 1
        = -----------------------------------------------------------------------------------------
             (r * (r-1) * (r-2) * ... * 3 * 2 * 1) * ((n-r) * (n-r-1) * (n-r-2) * ... * 3 * 2 * 1)

Now, if we assume, r is minimum of r and (n-r), we can rewrite the formula as,

             n * (n-1) * (n-2) * ... * (n-r+2) * (n-r+1)
        = ------------------------------------------------
                     r * (r-1) * (r-2) * ... * 3 * 2 * 1

We will now find numerator and denominator using modular multiplication w.r.t. (10^9 + 7) and then we need to divide numerator by denominator. Dividing by denominator is equivalent to multiplying numerator with the inverse of denominator w.r.t. (10^9 + 7). So, we find inverse of denominator and multiply it with the numerator.

Now, we have all the three results mentioned above w.r.t. (10^9 + 7). And finally, simple modular multiplication of 3 values will yield the desired result.

Solution:

#include<cstdio>
#include<iostream>
#include<string>
#include<cstdlib>
#include<queue>
#include<stack>
#include<utility>
#include<string>
#include<cstring>
#include<set>
#include<cmath>
#include<vector>
#include<fstream>
#include<map>
#include<list>
#include<algorithm>
#define MOD 1000000007

typedef long long int LLD;
typedef unsigned long long int LLU;

using namespace std;

LLD r[101];

LLD mod_power(LLD a, LLD n, LLD mod){

    // returns (a^n) % mod.
    // '%' represents modulus operation.

    LLD y = 1;
    while(n){
        if(n & 1)
            y = (y * a) % mod;
        a = (a * a) % mod;
        n >>= 1;
    }
    return y;
}

LLD inverse(LLD num){

    // returns the inverse of num w.r.t. (10^9 + 7).
    // uses the property a^(-1) mod p = a^(p-2) mod p.
    return mod_power(num, MOD - 2, MOD);
}

LLD find_ncr_mod(LLD n, LLD r){

    // returns the value of nCr mod (10^9 + 7).

    r = min(r, n-r);
    if(n == 0 || n == 1 || r == 0)
        return 1;

    // find numerator mod (10^9 + 7).
    LLD num = 1;
    for(LLD i = n;i >= n-r+1;i--)
        num = (num * i) % MOD;

    // find denominator mod (10^9 + 7).
    LLD den = 1;
    for(LLD i=2;i<=r;i++)
        den = (den * i) % MOD;

    // find the inverse of obtained denominator w.r.t. (10^9 + 7).
    den = inverse(den);

    // multiply numerator and inverse of denominator and return the result.
    LLD res = (num * den) % MOD;
    return res;
}

int main(){
 
    LLD n, w, t, r, res;
    scanf("%lld%lld%lld%lld", &n, &w, &t, &r);

    // find nCw.
    res = find_ncr_mod(n, w);
    n -= w;

    // find (n-w)Ct and multiply with previous value found.
    res = (find_ncr_mod(n, t) * res) % MOD;
    n -= t;

    // find (n-w-t)Cr and multiply with previous value found.
    res = (find_ncr_mod(n, r) * res) % MOD;
    printf("%lld\n", res);
    return 0;

}

Any suggestions are welcome.

5 comments:

  1. why need this line r=min(r,n-r);
    please explain this.thnks in advance

    ReplyDelete
  2. why we use r=min(r,n-r) rather than actual r !!!!!!! for finding nCr

    ReplyDelete
  3. That will just reduce the number of computations.

    Let's take an example to understand this.

    1. 6C2
    Here, r = 2, and (n-r) = 4.
    We calculate

    (6 * 5 * 4 * 3 * 2 * 1)
    -------------------------
    (2 * 1) * (4 * 3 * 2 * 1)

    which turns to,

    6 * 5
    ------
    2 * 1

    So, as you can see, the denominator turns out to be the factorial of min(4, 2), which is 2!.

    Let's take another example.

    2. 10C7
    Here, r = 7 and (n-r) = 3.

    we calculate
    (10 * 9 * 8 * 7 * 6 * 5 * 4 * 3 * 2 * 1)
    -----------------------------------------
    (7 * 6 * 5 * 4 * 3 * 2 * 1) * (3 * 2 * 1)

    which turns to,

    10 * 9 * 8
    -----------
    (3 * 2 * 1)

    So, here again, as you can see, the denominator turns out to be the factorial of min(3, 7) = 3!.

    Also, it reduces the number of multiplications to be done for the numerator part. That I'll leave on you to figure out.

    And, thus we use, r = min(r, n-r).

    Hope that answers your question.

    ReplyDelete
  4. Thanks for detail reply .i understood it.your email address please!!!!!!

    ReplyDelete

SPOJ Problem ONEZERO

Ones and zeros Explanation: A very good problem to practice BFS skills. I think that much hint is good to give the problem a shot. An...