Problem 40 asks for information that should be easily obtainable by a couple of for loops and a heap of processing power:

An irrational decimal fraction is created by concatenating the positive integers:

0.123456789101112131415161718192021…

It can be seen that the 12th digit of the fractional part is 1.

If _d_ _n_ represents the _n_th digit of the fractional part, find the value of the following expression.

_d_1 × _d_10 × _d_100 × _d_1000 × _d_10000 × _d_100000 × _d_1000000

The simple way to do this would be to construct a million-character string and then pull d[0], d[9], d[99], &c., convert each to an integer, and find the product. This turns out to be a very, very, unbearably slow approach, either because a million-character string is unwieldy or because for (int i = 1; decimalFraction.Length <= 1000000; i++) { decimalFraction += i.ToString(); } takes a long time to execute.

Thankfully, it's possible to solve this problem without actually constructing 1,000,000 digits of the irrational number described. If you conceive of the string as the result of the for loop at the end of the preceding paragraph, then it becomes clear that any one digit taken from the irrational number is part of a whole integer i. The trick is to find out which i the digit is part of, and then one can quickly find the solution to the problem.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Problem040
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Problem 40: {0}", (charAt(1) * charAt(10) *
                                                  charAt(100) * charAt(1000) *
                                                  charAt(10000) * charAt(100000) *
                                                  charAt(1000000)));
        }

        private static int charAt(int decimalPlace)
        {
            int startOfTwoDigitNums = 10;
            int startOfThreeDigitNums = 2 * 90 + startOfTwoDigitNums;
            int startOfFourDigitNums = 3 * 900 + startOfThreeDigitNums;
            int startOfFiveDigitNums = 4 * 9000 + startOfFourDigitNums;
            int startOfSixDigitNums = 5 * 90000 + startOfFiveDigitNums;
            int startOfSevenDigitNums = 6 * 900000 + startOfSixDigitNums;
            int numOfDigits = 0;
            int startingPlace = 0;
            int whichDigit = 0;
            int numAtDigit = 0;

            if (decimalPlace < startOfTwoDigitNums)
            {
                numOfDigits = 1;
                return decimalPlace;
            }
            else if (decimalPlace < startOfThreeDigitNums)
            {
                numOfDigits = 2;
                startingPlace = startOfTwoDigitNums;
            }
            else if (decimalPlace < startOfFourDigitNums)
            {
                numOfDigits = 3;
                startingPlace = startOfThreeDigitNums;
            }
            else if (decimalPlace < startOfFiveDigitNums)
            {
                numOfDigits = 4;
                startingPlace = startOfFourDigitNums;
            }
            else if (decimalPlace < startOfSixDigitNums)
            {
                numOfDigits = 5;
                startingPlace = startOfFiveDigitNums;
            }
            else if (decimalPlace < startOfSevenDigitNums)
            {
                numOfDigits = 6;
                startingPlace = startOfSixDigitNums;
            }

            whichDigit = (decimalPlace - startingPlace) % numOfDigits;
            numAtDigit = (((decimalPlace - startingPlace) / numOfDigits)
                          + (int)Math.Pow(10, (numOfDigits - 1)));
            numAtDigit = numAtDigit.ToString()[whichDigit] - 48;

            return numAtDigit;
        }
    }
}