I'd like to thank the writers of the contest analysis for taking the time to 
explain not just a solution for this problem, but a general technique that can 
be used to solve other problems. It took me a lot of effort to understand the 
analysis and the sample solutions provided, and as part of that effort I wrote 
some other programs. I am sharing those programs with my own notes in case it 
will help people who need an even more detailed explanation. Any comments or 
corrections gratefully accepted.

I will submit three programs:

1) A decimal version of the "count" function provided in the analysis
2) My version of the problem B solution. It is a bit longer than the reference 
solution, but it requires less case-analysis. For example, if the problem said 
the special operation is "OR" instead of "AND", my version requires no thought 
to change.
3) I made up another problem and show how to solve it using the general decimal 
solution template.

///////////////////////////////////////////
// Demo 1: decimal version of count() function from analysis
///////////////////////////////////////////
#include <iostream>
#include <string.h>

using namespace std;

typedef long long LL;

// adjust memo size depending on desired size of M
int memo[10][2];

int getDigit(int M, int p)
{
        while (p--)
        {
                M /= 10;
        }
        return M%10;
}

// Function count(...,M) provides a template for counting the number of 
integers less than M
// Given a decimal integer M, it returns exactly M.
// However, the method of counting can be adapted to answer many questions of 
the type "How many integers less than M satisfy some condition".

// More specifically, count(p, prefixIsLess, M) is counting those numbers which 
satisfy the following conditions:
//    Their "prefix" of digits to the left of position p, are either LESS THAN, 
or EQUAL TO, the corresponding prefix of M,
//        as indicated by the parameter prefixIsLess:
//              if that parameter is true, then count those numbers for whom 
their prefix is LESS
//              otherwise count those numbers for whom the prefix is EQUAL TO 
the same prefix of M.
//
// Note that p=0 is the least significant digit position.
//
// Example: suppose M = 56789
// count(2, true,   M) will return the count for any pattern such as 55dxx, 
54dxx, 53dxx,..., 00dxx.
//              In this case the prefix is LESS. So, digit "d" in position p=2 
can range from 0..9, because any number with such a prefix is less than M 
already.
//              Say the prefix is 54.
//              The return value is 1000 because dxx from range from 000..999 
and all such numbers 54000..54999 are less than M.
//
// count(2, false,  M) will return count of all the numbers with the pattern 
56dxx
//              In this case, the prefix is EQUAL to 56. So the digit in 
position p (indicated by "c" above) can only count up to 7.
//              The return value is 789 because dxx can range from 000..788 and 
the numbers 56000..56788 are less than M.
//
// Because these "dxx" types of subproblems are repeatedly calculated 
recursively, memoization is used to cache the results
//
// We can start out with "p" being in some far left position that is guaranteed 
to be bigger than M, so the first few prefixes we build are all 0.
//
int count(int p, bool prefixIsLess, int M)
{
        if (p == -1)
                return prefixIsLess ? 1 : 0;

        int& r = memo[p][prefixIsLess];
        if (r != -1)
                return r;
        r = 0;
        int pM = getDigit(M, p);
        // Generate the possible digits in position p, based on the prefix 
status of EQUAL or LESS
        // If the status is LESS then position p can range up to 9
        // Otherwise status is EQUAL, and position p can range only up to 
whatever is in position p of M
        for (int d = 0; d <= (prefixIsLess?9:pM); d++)
        {
                r += count(p-1, prefixIsLess||(d<pM), M); // Update the prefix 
status of the new prefix which is one digit longer
        }
        return r;
}

int main()
{
        int T;
        // some samples
        memset(memo, -1, sizeof(memo));
        cout << count(2, false, 56789) << endl;
        memset(memo, -1, sizeof(memo));
        cout << count(2, true, 56789) << endl;

        cout << "Enter number of test cases:" << endl;
        cin >> T;
        for (int testCase = 1; testCase <= T; testCase++)
        {
                int M;
                cout << "Enter M:" << endl;
                cin >> M;
                memset(memo, -1, sizeof(memo));
                cout << count(8, false, M) << endl; // boring output
        }
        return 0;
}

-- 
You received this message because you are subscribed to the Google Groups 
"Google Code Jam" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To post to this group, send email to [email protected].
To view this discussion on the web visit 
https://groups.google.com/d/msgid/google-code/0d48352a-3ce6-4cfd-b108-63f3d6af02e6%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to