0

I have a problem with one task, so if you could help me a little bit.

Numbers are "lucky" or "unlucky". Number is "lucky" just if every digit 7 or every digit is 4. So "lucky" numbers are for example 4, 44, 7, 77. "Unlucky" are the others numbers.
You will get sequence of n-elements and number K. Your task is to compute number of all possible k-elements subsequence, which fulfill a one condition. The condition is that in the subsequence mustn't be two same "lucky" numbers. So for example there mustn't 77 and 77... Output number of all possible k-elements subsequence mod 10^9+7 0 < N,K < 10^5

Few examples:
Input:

5 2
7 7 3 7 77
Output:

7

Input:

5 3
3 7 77 7 77
Output:

4

Input:

34 17
14 14 14 ... 14 14 14
Output:

333606206

I have code which seems to work, but it is too slow when I try to compute binomial coefficient. I'm using map. In string I store number in string format. In second - int - part of the map is number which represents how many times was that number(in the first map parameter) used. So now I have stored every "unlucky" numbers stored together. Also every same "lucky" number is together. When I have it stored like this, I just compute all multiplications. For example:

Input 
5 2
3 7 7 77 7
Are stored like this:  map["other"] = 1 map["7"] = 3 map["77"] = 1 
Because k = 2 --> result is: 1*3 + 1*1 + 1*3 = 7.

I think problem is with computing binomial coefficient. For the third example it needs to compute (34 choose 17) and it is computing very long time.I've found this article and also this , but I don't understand how they are solving this problem.

My code:

#include<iostream>
#include<string>
#include<map>
#include <algorithm>
#include <vector>

using namespace std;

int binomialCoeff(int n, int k)
{
    // Base Cases
    if (k == 0 || k == n)
        return 1;

    // Recur
    return  binomialCoeff(n - 1, k - 1) + binomialCoeff(n - 1, k);
}

int main()
{
    int n, k;
    cin >> n >> k;
    map<string, int> mapa;  // create map, string is a number, int represents number of used string-stored numbers ---> so if 7 was used two times, in the map it will be stored like this mapa["7"] == 2 and so on)
    for (int i = 0; i < n; i++)  // I will load number as string, if this number is "lucky" - digist are all 7 or all 4
    {                            // every "unlucky" numbers are together, as well as all same "lucky" numbers ---> so 77 and 77 will be stored in one element....
        string number;
        cin >> number;
        char digit = number[0];
        bool lucky = false;
        if (digit == '7' || digit == '4')
            lucky = true;
        for (int j = 1; j < number.length(); j++) {
            if (digit != '7' && digit != '4')
                break;
            if (number[j] != digit) {
                lucky = false;
                break;
            }
        }
        if (lucky)
            mapa[number]++;
        else
            mapa["other"]++;
    }
    vector<bool> v(mapa.size());
    bool lack = k > mapa.size(); //lack of elements in map --> it is when mapa.size() < k; i. e. number of elements in array can't make k-element subsequence.
    int rest = lack ? k - mapa.size() + 1 : 1;  // how many elements from "unlucky" numbers I must choose, so it makes base for binomial coefficient (n choose rest)
    if (lack)  //if lack is true, different size of vector
        fill(v.begin() + mapa.size(), v.end(), true);
    else
        fill(v.begin() + k, v.end(), true);
    int *array = new int[mapa.size()];   //easier to manipulate with array for me
    int sum = 0;  
    int product = 1;
    int index = 0; 
    for (map<string, int> ::iterator pos = mapa.begin(); pos != mapa.end(); ++pos)  // create array from map
    {
        if (lack && pos->first == "other") {    //if lack of elements in map, the number in elemets representing "unlucky" numbers will be binomial coefficient (mapa["other] choose rest)
            array[index++] = binomialCoeff(mapa["other"], rest);
            continue;
        }
        array[index++] = pos->second;
    }
    do {   // this will create every posible multiplication for k-elements subsequences
        product = 1;
        for (int i = 0; i < mapa.size(); ++i) {
            if (!v[i]) {
                product *= array[i];
            }
        }
        sum += product;
    } while (next_permutation(v.begin(), v.end()));
    if (mapa["other"] >= k && mapa.size() > 1) {   // if number of "unlucky" numbers is bigger than k, we need to compute all possible  k-elements subsequences just from "unlucky" number, so binomial coefficient (mapa["other] choose k)
        sum += binomialCoeff(mapa["other"], k);
    }
    cout << sum % 1000000007 << endl;
}
Community
  • 1
  • 1
Jozef Bugoš
  • 137
  • 1
  • 2
  • 8
  • First things first. Find a different method for computing binomial coefficients (google for it). You are using just about the worst possible method imaginable. Bear in mind that binomial coefficients you need will overflow `int` in your examples. – n. m. could be an AI Nov 16 '15 at 23:05
  • Yeah, I know. I've found [this article](http://stackoverflow.com/questions/3537360/calculating-binomial-coefficient-nck-for-large-n-k) and also [this](http://stackoverflow.com/questions/13106587/binomial-coefficient-modulo-142857) , but I don't understand how to do it. It needs to be very fast, I suppose, 'cause in my case, both 0 < N,K <= 10^5 – Jozef Bugoš Nov 17 '15 at 08:33
  • This looks like a perfect match for being solved in a haskell oneliner :/ – Netwave Nov 17 '15 at 08:56
  • 1
    What is the range of number in the sequence? – Pham Trung Nov 17 '15 at 09:38
  • Some hint: the number of distinct lucky number will be small, only less than 1000 numbers (maximum 9 digits, so 2^9 + 2^8 + ... + 2 ~ 1000), which you can use dynamic programming to calculate the lucky number part. For unlucky number part, as we only need to calculate 1000 [combinations](http://www.mathwords.com/c/combination_formula.htm), We can use [Fermat's little theorem](https://en.wikipedia.org/wiki/Fermat%27s_little_theorem) to handle. – Pham Trung Nov 17 '15 at 16:07
  • You're right. In fact, there are just 18 types of lucky numbers, aren't there? 4,44,444....444444444 and the same for 7. Also, I don't understand how to use Fermat's little theorem to compute combinations. – Jozef Bugoš Nov 17 '15 at 19:23
  • For combination `C(a, b) = a! / (b! (a - b)!)`, and we need to calculate `C(a, b) mod 10^9 + 7`, we can not directly calculate the mod of C(a, b), however, notice that 10^9 + 7 is a prime number, so, we can use the theorem, see one explanation [here](http://codeforces.com/blog/entry/5679) – Pham Trung Nov 18 '15 at 02:46
  • So, I've found [this article](https://codeaccepted.wordpress.com/2014/02/15/output-the-answer-modulo-109-7/), and now I have code, that works just fine :) – Jozef Bugoš Nov 18 '15 at 20:52
  • Great :), next time, please use `@` + `Name` to notify the person you are talking to, for example @PhamTrung to notify me :D – Pham Trung Nov 19 '15 at 03:47
  • @PhamTrung thanks, i will remember that :) – Jozef Bugoš Nov 19 '15 at 06:31

0 Answers0