// ================================================================================================ // Problem 32 // ================================================================================================ sint32 Problem32() { CTable<uintn> products; // -- first handle single digit numbers // -- one can't work, because it would result in identical multiplier and product for(uintn i = 2; i <= 9; ++i) FindProducts(i, uintn(1) << i, products); // -- then double digit numbers for(uintn i = 1; i <= 9; ++i) { for(uintn j = 1; j <= 9; ++j) { if(i == j) continue; FindProducts(i*10 + j, uintn(1) << i | uintn(1) << j, products); } } // -- add all the products we collected in our table uintn result = 0; uintn count = products.Count(); for(uintn i = 0; i < count; ++i) result += products[i]; CLog::Write("The sum of the products is " UintNFmt_ "\n", result); Assert_(result == kAnswer, "The answer should have been " UintNFmt_, kAnswer); return 0; }
// ------------------------------------------------------------------------------------------------ // Get the length of the recurring cycle (zero if it doesn't repeat at all) // ------------------------------------------------------------------------------------------------ static uintn CycleLength(uintn denom) { uintn curr = 1; CTable<uintn> remain; while(curr != 0) { curr *= 10; uintn div = curr / denom; curr -= denom * div; remain.Grow(curr); // -- look through the previous remainders to see if we've started repeating for(uintn i = remain.Count() - 1; i > 0;) { --i; if(remain[i] == curr) return remain.Count() - 1 - i; } } // -- if we exited the loop, we finished the decimal expansion, so there's no cycle return 0; }
// ------------------------------------------------------------------------------------------------ // Recursive function to collect all the combinations of factors // ------------------------------------------------------------------------------------------------ void CFactorizer::CollectFactorCombinations(const CTable<nuint>& factors, nuint curr, nuint prod, CTable<nuint>& divisors) { nuint numfactors = factors.Count(); nuint f = factors[curr]; // -- look for the upper bound of the same factor nuint end = curr; while(end < numfactors && factors[end] == f) ++end; // -- figure out if we're the end of the line and so we should be adding into the table nflag record = end == numfactors; // -- loop over the number of times this factor is repeated and deal with all of them for(nuint i = curr; i <= end; ++i) { if(record) divisors.Grow(prod); else CollectFactorCombinations(factors, end, prod, divisors); prod *= f; } }
// ------------------------------------------------------------------------------------------------ // Iterate over all the possible multipliers for the given multiplicand // ------------------------------------------------------------------------------------------------ static void FindProducts(uintn a, uintn digitbits, CTable<uintn>& products) { uintn min = 1234 / a; uintn max = 9876 / a; // -- if a is a single digit, then the second operand needs to be 4 digits if(a < 10 && min < 1234) min = 1234; // -- if a is double digit, then the second operand needs to be 3 digits if(a >= 10) { if(min < 123) min = 123; if(max > 987) max = 987; } // -- if we've already ruled out the possibility of any results, just return if(max < min) return; // -- get the digits for the min, and then iterate up through the max uintn digits[4]; uintn curr = min - 1; for(uintn i = 0; i < 4; ++i) { digits[i] = curr % 10; curr /= 10; } // -- now iterate until we reach max curr = min - 1; while(curr <= max) { // -- look until we see a number with digits that don't overlap with the input flagn illegal = true; uintn currbits = digitbits; while(illegal) { // -- increment the ones digit ++digits[0]; if(digits[0] > 9) { digits[0] = 1; ++digits[1]; if(digits[1] > 9) { digits[1] = 1; ++digits[2]; if(digits[2] > 9) { digits[2] = 1; ++digits[3]; } } } // -- first update curr to be the new value curr = digits[0] + digits[1]*10 + digits[2]*100 + digits[3]*1000; if(curr > max) return; // -- then check the current digits to see if they are worth checking currbits = digitbits; illegal = false; for(uintn i = 0; i < 4 && !illegal; ++i) { // -- if we're zero and a higher digit is not zero (we're not a leading zero) // -- then this is an invalid number if(digits[i] == 0) { if(i+1 < 4 && digits[i+1] != 0) { illegal = true; break; } } else { // -- if this digit has already been done, keep looking if((currbits & (uintn(1) << digits[i])) != 0) { illegal = true; break; } // -- record this digit in the current bits currbits = currbits | uintn(1) << digits[i]; } } } uintn product = a * curr; // -- then look at each digit illegal = false; while(product > 0) { uintn digit = product % 10; product /= 10; // -- check to see if it's zero if(digit == 0) { illegal = true; break; } if((currbits & (uintn(1) << digit)) != 0) { illegal = true; break; } currbits = currbits | (uintn(1) << digit); } // -- if it's not illegal and we've found each digit from 1 to 9 if(!illegal && currbits == kAllNine) { product = a * curr; // -- look through the existing products, and make sure it's not already there uintn count = products.Count(); uintn i = 0; for(; i < count; ++i) { if(products[i] == product) break; } if(i == count) products.Grow(product); else CLog::Write("-repeat- "); CLog::Write(UintNFmt_ " x " UintNFmt_ " = " UintNFmt_ "\n", a, curr, product); } } }