Dynamic Programming: Counting numbers in between - c++

Given two numbers X and Y, how many numbers exist between them inclusive that have at least half their digits the same? For example, 1122 and 4444 would work, while 11234 and 112233 would not work.
Obviously, the most straightforward way is to start at X and increment by 1 all the way to Y, and then check each number, but that is way too slow, as the boundaries for X and Y are between 100 and 10^18. I know that it is some form of dynamic programming, and that I should use strings to represent the numbers, but I can't get much further.
Any help would be accepted. Thanks!

I will explain you in some steps:
First step:
For solving this kind of range problems between X and Y always make it simple by counting between 0 to X and 0 to Y-1, then subtract the result. i.e. if you have a function like f(N) that calculates the numbers that have at least half their digits the same between 0 and N, then your final result is:
f(X) - f(Y-1)
Second step:
Next we have to compute f(N). We split this function into 2 sub functions, one for calculating the result for numbers having the same number of digits with N (lets call it f_equal), and the other for counting the qualified numbers having digits less the N (let's call it f_less). E.g. if N is 19354, we count the qualified numbers between 0 to 9999, then in another method count the favorite numbers between 10000 to 19354, after that we sum up the result. Next, I'll explain you how to implement these two methods.
Third step:
Here, we want to compute f_less method. you can do it by some math, but I always prefer to write a simple DP for solving these tasks. I will write the recursive function whether you can use memoization or you can make it bottom-up with some loops (I'll leave it as a practice for you).
long long f_less(int curDigit, int favNum, int favNumCountSoFar, int nonFavNum, int nonFavNumCountSoFar, int maxDigit){
if(curDigit == maxDigit ){
//for numbers with even maxDigit there may be a case when we have 2 favorite numbers
//and we should count them only once. like 522552
if(favNumCountSoFar*2 == maxDigit && favNumCountSoFar == nonFavNumCountSoFar) return 1;
if(2*favNumCountSoFar >= maxDigit) return 2;
return 0;
}
long long res = 0;
for(int i=(curDigit==0?1:0);i<=9;++i) //skip the leading zero
if(i==favNum)
res += f_less(curDigit+1, favNum, favNumCountSoFar + 1, nonFavNum, nonFavNumCountSoFar,maxDigit);
else
res += f_less(curDigit+1, favNum, favNumCountSoFar, i, (i==nonFavNum?nonFavNumCountSoFar+1:1),maxDigit);
return res;
}
And call it for all numbers through 0 to 9:
long long res = 0;
for(int maxDigit = 1; maxDigit < NUMBER_OF_DIGITS(N); ++maxDigit)
for(int favNumber = 0; favNumber < 10; ++favNumber)
res += f_less(0, favNumber, 0, -1, 0, maxDigit);
Fourth Step:
Finally we have to compute f_equal. Here we have to keep the number in a string to always check whether we are still in the range below N or not in the recursive function. Here is the implementation of f_equal (again use memoization or make it bottom-up):
string s = NUM_TO_STRING(N);
int maxDigit = s.size();
long long f_equal(int curDigit, int favNum, int favNumCountSoFar,int nonFavNum, int nonFavNumCountSoFar, bool isEqual){ //isEqual checks that whether our number is equal to N or it's lesser than it
if(curDigit == maxDigit ){
//for numbers with even maxDigit there may be a case when we have 2 favorite numbers
//and we should count them only once. like 522552
if(favNumCountSoFar*2 == maxDigit && favNumCountSoFar == nonFavNumCountSoFar) return 1;
if(2*favNumCountSoFar >= maxDigit) return 2;
return 0;
}
long long res = 0;
for(int i=(curDigit==0?1:0);i<=9;++i){ //skip the leading zero
if(isEqual && i>(s[curDigit]-'0')) break;
if(i==favNum)
res += f_equal(curDigit+1, favNum, favNumCountSoFar + 1, nonFavNum, nonFavNumCountSoFar, isEqual && (i==(s[curDigit]-'0')));
else
res += f_equal(curDigit+1, favNum, favNumCountSoFar, i, (i==nonFavNum?nonFavNumCountSoFar+1:1), isEqual && (i==(s[curDigit]-'0')));
}
return res;
}
And call it:
long long res = 0;
for(int favNumber = 0; favNumber < 10; ++favNumber)
res += f_equal(0, favNumber,0, -1, 0, true);
The final result is res/2. The code is tested and works well.

Obviously, then, you won't do this by considering all numbers in the range. Instead, think in terms of generating the numbers you want. For instance, design a function that will generate all of the qualifying numbers, given no more than the length in digits.
For instance, for 5 digits, you want all the numbers with at least three 1's, or three 2's, or ... Can you do that in one pass, or do you need to separate those with exactly three 1's from those with more?
Now that you've thought about that, think about this: instead of generating all those numbers, just count them. For instance, for three 1's and two other digits, you have 9*9 pairs of other digits (make sure not to double-count things such as 11122). You can arrange the 1's in 10 ways, with a possible swap of the other two digits.
Note that the problem is a little different with an even quantity of digits: you have to avoid double-counting the half-and-half numbers, such as 111222.
Does that get you moving?
RESPONSE TO COMMENTS 03 Dec
#bobjoe628: this is not intended to be a complete algorithm; rather, it's a suggestion to get you started. Yes, you have several combinatoric problems to handle. As for 11122233, I'm not sure I understand your concern: as with any such permutation problem, you have to handle each digit being interchangeable with its siblings. There are 10C5 ways to distribute the 1's; in the remaining spots, there are 5C3 ways to distribute the 2's; the other two slots are 3'3. Readily available algorithms (i.e. browser search) will cover those machinations.
I trust that you can write an algorithm to generate numbers: note that you need only one combination of digits, so it's safe to simply generate digits in ascending order, as you've been giving your examples: 1111122233. Once you've generated that, your combinatoric code should cover all unique permutations of those digits.
Finally, note that most languages have support packages that will perform permutations and combinations for you.

The number 0 is just shorthand. In reality there are an infinite number of leading zeros and an infinite number of trailing zeros (after the decimal point), like ...000000.000000....
For all integers it's obvious that there are at least as many 0s after the decimal point as there are non-zero digits before the decimal point; so all integers can be counted.
There are an infinite number of numbers between 0 and 1; and all of these have at least as many 0s to the left of the decimal point as they have non-zero digits after the decimal point. The same applies to numbers between 0 and -1.
For almost all floating point numbers that a computer can store, there simply isn't enough bits to cancel out all the leading and trailing zeros.
The only numbers that can't be counted are positive and negative infinity, and some but not all irrational numbers that are <= 1 or >= -1.
Code:
float getCount(int x, int y) {
if(x == y) return 0.0; // Special case (no numbers are between x and y)
return INFINITY; // The closest value to the correct answer that a computer can use
}

Here is a partial combinatoric answer. I leave out how to use the function to construct a full answer.
(Please see here for the same code with more elaborate comments: https://repl.it/#gl_dbrqn/AllSteelblueJuliabutterfly)
Fixing the leftmost digit(s), L, in a number with R digits to the right of L, we can calculate how many ways we can distribute (N / 2) or more of digit d by:
Python Code
import math, operator, collections
# Assumes L has at least one digit set
# f({'string':'12', 'digit_frequencies':[0,1,1,0,0,0,0,0,0,0], 'num_digit_frequencies': 2}, 6)
def f(L, N):
R = N - len(L['string'])
count = 0
counted = False
for digit_frequency in L['digit_frequencies']:
start = int(math.ceil(N / 2.0)) - digit_frequency
if start > R:
continue
for i in xrange(start, R + 1):
if not (N & 1) and not counted:
if L['num_digit_frequencies'] == 1 and not digit_frequency and i == N / 2:
count = count - choose(R, i)
if L['num_digit_frequencies'] == 2 and digit_frequency and not any([x > N / 2 for x in L['digit_frequencies']]) and i + digit_frequency == N / 2:
count = count - choose(R, i)
counted = True
m = 9**(R - i)
n = R - i + 1
k = i
count = count + m * choose(n + k - 1, k)
return count
# A brute-force function to confirm results
# check('12', 6)
def check(prefix, length):
result = [x for x in xrange(10**(length - 1), 10**length) if len(str(x)) == length and str(x).startswith(prefix) and isValid(str(x))]
print result
return len(result)
def isValid(str):
letters = collections.Counter(str)
return any([x >= math.ceil(len(str) / 2.0) for x in letters.values()])
# https://stackoverflow.com/questions/4941753/is-there-a-math-ncr-function-in-python
def choose(n, r):
r = min(r, n-r)
if r == 0: return 1
numer = reduce(operator.mul, xrange(n, n-r, -1))
denom = reduce(operator.mul, xrange(1, r+1))
return numer//denom

Related

How to compute first N digits of Euler number in c++? [duplicate]

Can anyone explain how this code for computing of e works? Looks very easy for such complicated task, but I can't even understand the process. It has been created by Xavier Gourdon in 1999.
int main() {
int N = 9009, a[9009], x = 0;
for (int n = N - 1; n > 0; --n) {
a[n] = 1;
}
a[1] = 2, a[0] = 0;
while (N > 9) {
int n = N--;
while (--n) {
a[n] = x % n;
x = 10 * a[n-1] + x/n;
}
printf("%d", x);
}
return 0;
}
I traced the algorithm back to a 1995 paper by Stanley Rabinowitz and Stan Wagon. It's quite interesting.
A bit of background first. Start with the ordinary decimal representation of e:
e = 2.718281828...
This can be expressed as an infinite sum as follows:
e = 2 + 1⁄10(7 + 1⁄10(1 + 1⁄10(8 + 1⁄10(2 + 1⁄10(8 + 1⁄10(1 ...
Obviously this isn't a particularly useful representation; we just have the same digits of e wrapped up inside a complicated expression.
But look what happens when we replace these 1⁄10 factors with the reciprocals of the natural numbers:
e = 2 + 1⁄2(1 + 1⁄3(1 + 1⁄4(1 + 1⁄5(1 + 1⁄6(1 + 1⁄7(1 ...
This so-called mixed-radix representation gives us a sequence consisting of the digit 2 followed by a repeating sequence of 1's. It's easy to see why this works. When we expand the brackets, we end up with the well-known Taylor series for e:
e = 1 + 1 + 1/2! + 1/3! + 1/4! + 1/5! + 1/6! + 1/7! + ...
So how does this algorithm work? Well, we start by filling an array with the mixed-radix number (0; 2; 1; 1; 1; 1; 1; ...). To generate each successive digit, we simply multiply this number by 10 and spit out the leftmost digit.*
But since the number is represented in mixed-radix form, we have to work in a different base at each digit. To do this, we work from right to left, multiplying the nth digit by 10 and replacing it with the resulting value modulo n. If the result was greater than or equal to n, we carry the value x/n to the next digit to the left. (Dividing by n changes the base from 1/n! to 1/(n-1)!, which is what we want). This is effectively what the inner loop does:
while (--n) {
a[n] = x % n;
x = 10 * a[n-1] + x/n;
}
Here, x is initialized to zero at the start of the program, and the initial 0 at the start of the array ensures that it is reset to zero every time the inner loop finishes. As a result, the array will gradually fill with zeroes from the right as the program runs. This is why n can be initialized with the decreasing value N-- at each step of the outer loop.
The additional 9 digits at the end of the array are presumably included to safeguard against rounding errors. When this code is run, x reaches a maximum value of 89671, which means the quotients will be carried across multiple digits.
Notes:
This is a type of spigot algorithm, because it outputs successive digits of e using simple integer arithmetic.
As noted by Rabinowitz and Wagon in their paper, this algorithm was actually invented 50 years ago by A.H.J. Sale
* Except at the first iteration where it outputs two digits ("27")

How make this even count code faster?

The following code is meant to find total numbers between l and r whose product of digits is even (for multiple test cases t). This code runs perfectly but is extremely slow for r greater than 100000. Can anyone suggest a better alternative?
#include <iostream>
#include <algorithm>
using namespace std;
long long int nd(long long int x, int n) //return the digit at a particular index staring with zero as index for unit place
{
while (n--) {
x /= 10;
}
return (x % 10);
}
int ng(long long int number) //returns total number of digits in an integer
{
int digits = 0;
if (number < 0) digits = 1;
while (number) {
number /= 10;
digits++;
}
return digits;
}
int main()
{
int t;
cin>>t;
long long int l[t], r[t], c;
for(long long int j=0;j<t;j++)
{
cin>>l[j]>>r[j];
}
for(long long int k=0;k<t;k++)
{
long long int sum=0;
long long int t=0;
for(long long int i=l[k];i<=r[k];i++)
{
while(t<ng(i))
{
c=nd(i,t);
if((c%2)==0)
{
++sum;
break;
}
++t;
}
t=0;
}
cout<<sum<<endl;
}
cin.ignore();
cin.get();
return 0;
}
The basic idea is to loop through each digit of a number and see if it's even. If it is, the whole product will be even and there's no need to check the remaining digits.
The problem with your code is that you run trough the number multiple times looking for a digit with index i. You should simply run through the number's digits once checking for evenness along the way.
Here's a self-explanatory Go code implementing the algorithm:
package main
func iseven(num int) bool {
for num > 0 {
digit := num % 10
if digit&1 == 0 { # same as digit%2 == 0, only simpler
return true
}
num /= 10
}
return false
}
func main() {
sum := 0
for n := 1; n < 1000000; n++ {
if iseven(n) {
sum++
}
}
println(sum)
}
Performance on my machine:
λ time go run main.go
980469
go run main.go 0.05s user 0.01s system 81% cpu 0.073 total
Update
If you need to work with ginormous numbers, then a more efficient approach can be used.
Let's call the numbers that have the product of their digits odd dodd numbers. So, 135 is a dodd number, 134 is not. Similarly, numbers that have the product of their digits even are called deven. So 134 is a deven number.
As has been mentioned earlier, only numbers that consist of odd digits are dodd. So instead of enumerating numbers, we can just count the numbers comprised of digits 1, 3, 5, 7, and 9. For integer N > 1, there are exactly 10^N - 10^(N-1) numbers that have N digits. And of those numbers, 5 ^ N are dodd, and therefore 10^N - 10^(N-1) - 5^N are deven.
The approach is to count how many dodd numbers there are in between the left and right bounds and then subtract that count from the total count of numbers between left and right. You could also count just deven numbers, but that is a bit trickier.
Effectively, you're going to loop through digits with this approach, instead of through numbers. My implementation in Python is able to compute the number of deven numbers between 1 and int("1" * 100000) (a number with 10000 digits) in under one second.
All numbers starting with, e.g., 10…, 12…, 14…, …, 2…, 30…, already are known to have an even product of digits. I would therefore start from the left (more significant digits) and count in blocks. There are only a few numbers whose product of digits is odd (such as 1111111111), only here you have to dig deeper.
Here is some pseudocode:
int count(String prefix, int digits) {
int result = 0;
if (digits == 0)
return 0;
for (int d = 0; d < 10; d++) {
if (d%2 == 0)
result += 10**(digits-1);
else
result += count(prefix . toString(d), digits-1);
}
return result;
}
This would be called like count("2", 8) to get the count for the interval from 200000000 to 299999999.
Here is a Haskell implementation for a whole block (i.e., all d-digit numbers):
blockcount :: Integer -> Integer
blockcount 0 = 0
blockcount d = 5 * 10^(d-1) + 5 * blockcount (d-1)
E.g., blockcount 1000 is calculated to be 9999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999066736381496781121009910455276182830382908553628291975378285660204033089024224365545559672902118897640405010069675757375784512478645967605158479182796069243765589333861674849726004924014098168488899509203734886881759487485204066209194821728874584896189301621145573518880530185771339040777982337089557201543830551112852533471993671631547352570738170137834797206804710506392882149336331258934560194469281863679400155173958045898786770370130497805485390095785391331638755207047965173135382342073083952579934063610958262104177881634921954443371555726074612482872145203218443653596285122318233100144607930734560575991288026325298250137373309252703237464196070623766166018953072125441394746303558349609375 in much less than a second.
You’d still have to add code that breaks your range into suitable blocks.
An optimisation based on the following would work:
Multiplying two numbers together gets you oddness / evenness according to the rule
even * even = even
odd * even = even * odd = even
odd * odd = odd
Therefore you only need to track the last digit of your number numbers.
I'm too old to code this but I bet it would be blisteringly quick as you only need to consider numbers between 0 and 9.
The only thing you need to check is if one of digits in the number is even. If it is, it will have 2 as a factor, and hence be even.
You also don't seem to remember where you are up to in digits - every time you increment t in your for loop, and then call nd(i,t), you count down from that t to zero in nd. This is quadratic in number of digits in the worst case. Better would be to simply break up the number into its component digits at the beginning.
I can't figure out what your code is doing, but the basic
principles are simple:
value % 10 is the low order digit
value /= 10 removes the low order digit
if any digit is even, then the product will be even.
This should lead to a very simple loop for each value. (You may
have to special case 0.)
Further optimizations are possible: all even numbers will have
a product of digits which is even, so you can iterate with
a step of 2, and then add in the number of evens (one half of
the range) afterwards. This should double the speed.
One further optimization: if the low order digit is even, the number itself is even, so you don't have to extract the low order digit to test it.
Another thing you could do is change
while(t<ng(i))
to
int d = ng(i);
while (t < d)
So ng is only called once per loop.
Also ng is just log(number)+1 (log base 10 that is)
I don't know is that will be quicker though.
First, please fix your indentation
Your code uses too many division and loops which cause a lot of delays
long long int nd(long long int x, int n) //return the digit at a particular index staring with zero as index for unit place
{
while (n--) {
x /= 10;
}
return (x % 10);
}
This can be fixed easily by a table lookup
long long int nd(long long int x, int n) //return the digit at a particular index staring with zero as index for unit place
{
long long int pow10[] = {1, 10, 100, 1000, 10000, 100000, 1000000, 10000000,
100000000, 1000000000, 10000000000, 100000000000,
1000000000000, 10000000000000, 100000000000000,
1000000000000000, 10000000000000000,
100000000000000000, 1000000000000000000};
return ((x / pow10[n]) % 10);
}
Likewise, the ng function to get total number of digits in an integer can be changed to a fast log10, no need to repeatedly divides and count. Ofcourse it'll need a small change to adapt 64 bit numbers
int ng(long long int number) //returns total number of digits in an integer
{
int digits = 0;
if (number < 0) digits = 1;
while (number) {
number /= 10;
digits++;
}
return digits;
}

Find the perfect square in the string

A perfect square is taken in binary and some bits are replaced with "?" for example 1??, the number would be 4.(or 1????000???0000)
I need to find that perfect square.(there will be only such possible number)
number of '?'s in the string be n
To find that number what I am doing is iterating through 2**n numbers(111,110,101,100) and checking if it is a perfect square. I am using following function to check if it is a perfect square.
bool issqr(int n){
int d=(int)(sqrt(n));
if(d*d==n) return true;
else return false;
}
Even though in python I did it, it is taking a lot of time, so I shifted to C++ using only bit operations for populating 2**n numbers(which was much faster than the python version)
but this fails if the number has more than 64 bits
How to avoid this problem? How can I do the same thing if a number has say 120 bits.
(10100110???1?1?01?1?011000?1100?00101000?1?11001101100110001010111?0?1??0110?110?01?1100?1?0110?1?10111?01?0111000?10??101?01)
Rather than re-writing in C++ you should first have looked at improving your algorithm. The lowest possible answer is the square root from the original value with all '?' replace by 0 rounded up, the highest possible answer is the square root of the pattern with the '?'s replaced by 1 rounded down. Find those two values, iterate through them, square and check against the pattern.
This is faster both because you are iterating through many fewer numbers and because you aren't calculating any square roots in the loop: squaring is much easier.
You don't need to compare string to check for a match:
mask = int(pattern.replace('0', '1').replace('?', '0'), 2)
test = int(pattern.replace('?', '0'), 2)
def is_match(n):
return (n&mask)==test
So putting it all together:
def int_sqrt(x):
if x < 0:
raise ValueError('square root not defined for negative numbers')
n = int(x)
if n == 0:
return 0
a, b = divmod(n.bit_length(), 2)
x = 2**(a+b)
while True:
y = (x + n//x)//2
if y >= x:
return x
x = y
def find_match(pattern):
lowest = int(pattern.replace('?', '0'), 2)
highest = int(pattern.replace('?', '1'), 2)
mask = int(pattern.replace('0', '1').replace('?', '0'), 2)
lowsqrt = int_sqrt(lowest)
if lowsqrt*lowsqrt != lowest:
lowsqrt += 1
highsqrt = int_sqrt(highest)
for n in range(lowsqrt, highsqrt+1):
if (n*n & mask)==lowest:
return n*n
print(find_match('1??1??1'))
print(find_match('1??0??1'))
print(find_match('1??????????????????????????????????????????????????????????????????????1??0??1'))
Output:
121
81
151115727461209345152081
N.B. This only works in Python 3.x, the last test will overflow range in Python 2.x
From my understanding, given an integer n you are trying to find a square number sq that matches :
2n - 1 < sq < 2n+1 - 1
This condition is the mathematic translation of "my number must have the form 1????" where there are n "?".
First, you can notice that if n is even, the number 2n is a perfect square and matches your condition (in binary, it is the number 1000...000 - n zeroes -).
If n is uneven (say n = 2.p + 1), then 2n+1 is a perfect square ((2p+1)2). Computing the following number will give you a perfect square :
(2p+1 - 1)2
To satisfy the first inequality, p must satisfy :
2n - 1 < (2p+1 - 1)2
Then
0 < 2n+1 - 2p+2 + 1 - 2n + 1,
Finally,
2n + 2 - 2p+2 > 0
Or
22p - 2p+1 + 1 > 0
If we consider the function that matches p with f(p) such that :
f(p) = 22p - 2p+1 + 1
This function is defined for each positive real number, and is strictly increasing. Moreover, f(0) = 0. Finally, the initial condition is satisfied when p > 0 !
For p = 0 - or n = 1 -, the problem does not have a valid solution.
You don't need to iterate trough all the 2**n numbers to find the perfect square, in fact you only need one fractional square operation:
Say you have integer n and you want to find the largest perfect square smaller or equal than n, let's call it m.
Then:
d = (int)sqrt(n);
m = d*d;
Explanation:
Assume there is a perfect square m' larger than m , this implies there is an integer d' so that: d' > d and d'*d' = m'.
But d' >=d+1 and (d+1)*(d+1) > n so m' > n in contradiction to our requirement m' <= n.
Now to your question:
in order to find the perfect squares just change to "1" all of the "?" and find the perfect square if it conforms to your string you got the number you're looking for, if not change just enough "?" from the msb to "0" so that the resulting number is smaller or equal to the perfect square you just found, and keep going until you find the perfect square or run out of options.
Your operations may be returning something too large for an integer...
http://www.cplusplus.com/doc/tutorial/variables/

Optimizing algorithm to find number of six digit numbers satisfying certain property

Problem: "An algorithm to find the number of six digit numbers where the sum of the first three digits is equal to the sum of the last three digits."
I came across this problem in an interview and want to know the best solution. This is what I have till now.
Approach 1: The Brute force solution is, of course, to check for each number (between 100,000 and 999,999) whether the sum of its first three and last three digits are equal. If yes, then increment certain counter which keeps count of all such numbers.
But this checks for all 900,000 numbers and so is inefficient.
Approach 2: Since we are asked "how many" such numbers and not "which numbers", we could do better. Divide the number into two parts: First three digits (these go from 100 to 999) and Last three digits (these go from 000 to 999). Thus, the sum of three digits in either part of a candidate number can range from 1 to 27.
* Maintain a std::map<int, int> for each part where key is the sum and value is number of numbers (3 digit) having that sum in the corresponding part.
* Now, for each number in the first part find out its sum and update the corresponding map.
* Similarly, we can get updated map for the second part.
* Now by multiplying the corresponding pairs (e.g. value in map 1 of key 4 and value in map 2 of key 4) and adding them up we get the answer.
In this approach, we end up checking 1K numbers.
My question is how could we further optimize? Is there a better solution?
For 0 <= s <= 18, there are exactly 10 - |s - 9| ways to obtain s as the sum of two digits.
So, for the first part
int first[28] = {0};
for(int s = 0; s <= 18; ++s) {
int c = 10 - (s < 9 ? (9 - s) : (s - 9));
for(int d = 1; d <= 9; ++d) {
first[s+d] += c;
}
}
That's 19*9 = 171 iterations, for the second half, do it similarly, with the inner loop starting at 0 instead of 1, that's 19*10 = 190 iterations. Then sum first[i]*second[i] for 1 <= i <= 27.
Generate all three-digit numbers; partition them into sets based on their sum of digits. (Actually, all you need to do is keep a vector that counts the size of the sets). For each set, the number of six-digit numbers that can be generated is the size of the set squared. Sum up the squares of the set sizes to get your answer.
int sumCounts[28]; // sums can go from 0 through 27
for (int i = 0; i < 1000; ++i) {
sumCounts[sumOfDigits(i)]++;
}
int total = 0;
for (int i = 0; i < 28; ++i) {
count = sumCounts[i];
total += count * count;
}
EDIT Variation to eliminate counting leading zeroes:
int sumCounts[28];
int sumCounts2[28];
for (int i = 0; i < 100; ++i) {
int s = sumOfDigits(i);
sumCounts[s]++;
sumCounts2[s]++;
}
for (int i = 100; i < 1000; ++i) {
sumCounts[sumOfDigits(i)]++;
}
int total = 0;
for (int i = 0; i < 28; ++i) {
count = sumCounts[i];
total += (count - sumCounts2[i]) * count;
}
Python Implementation
def equal_digit_sums():
dists = {}
for i in range(1000):
digits = [int(d) for d in str(i)]
dsum = sum(digits)
if dsum not in dists:
dists[dsum] = [0,0]
dists[dsum][0 if len(digits) == 3 else 1] += 1
def prod(dsum):
t = dists[dsum]
return (t[0]+t[1])*t[0]
return sum(prod(dsum) for dsum in dists)
print(equal_digit_sums())
Result: 50412
One idea: For each number from 0 to 27, count the number of three-digit numbers that have that digit sum. This should be doable efficiently with a DP-style approach.
Now you just sum the squares of the results, since for each answer, you can make a six-digit number with one of those on each side.
Assuming leading 0's aren't allowed, you want to calculate how many different ways are there to sum to n with 3 digits. To calculate that you can have a for loop inside a for loop. So:
firstHalf = 0
for i in xrange(max(1,n/3),min(9,n+1)): #first digit
for j in xrange((n-i)/2,min(9,n-i+1)): #second digit
firstHalf +=1 #Will only be one possible third digit
secondHalf = firstHalf + max(0,10-|n-9|)
If you are trying to sum to a number, then the last number is always uniquely determined. Thus in the case where the first number is 0 we are just calculating how many different values are possible for the second number. This will be n+1 if n is less than 10. If n is greater, up until 18 it will be 19-n. Over 18 there are no ways to form the sum.
If you loop over all n, 1 through 27, you will have your total sum.

Finding optimal substructure

I'm looking for some pointers about a dynamic programming problem. I cannot find any relevant information about how to solve this kind of problem.
Problem
A number is called a special number if it doesn't contain 3 consecutive
zeroes. i have to calculate the number of positive integers of exactly d digits
that are special answer should be modulo 1000000007(just for overflow in c++).
Problem can easily solved by permutation and combination but i want it with dynamic programming.
I am unable to find its optimal substructure or bottom to top approach.
Let f(d,x) be the amount of most significant d digits whose last x digits are zeros, where 0 ≤ x ≤ 2. For d > 1, We have the recurrence:
f(d,0) = (f(d-1,0) + f(d-1,1) + f(d-1,2)) * 9 // f(d,0) comes from any d-1 digits patterns appended a non-zero digit
f(d,1) = f(d-1,0) // f(d,1) comes from the d-1 digits patterns without tailing zeros appended by a zero
f(d,2) = f(d-1,1) // f(d,2) comes from the d-1 digits patterns with one tailing zero appended by a zero
And for d = 1, we have f(1,0) = 9, f(1,1) = 0, f(1,2) = 0.
The final answer for the original problem is f(d,0) + f(d,1) + f(d,2).
Here is a simple C program for demo:
#include <cstdio>
const int MOD = 1000000007;
long long f[128][3];
int main() {
int n;
scanf("%d",&n);
f[1][0] = 9;
for (int i = 2 ; i <= n ; ++i) {
f[i][0] = (f[i-1][0] + f[i-1][1] + f[i-1][2]) * 9 % MOD;
f[i][1] = f[i-1][0];
f[i][2] = f[i-1][1];
}
printf("%lld\n", (f[n][0] + f[n][1] + f[n][2]) % MOD);
return 0;
}
NOTE: i haven't tested out my logic thoroughly, so please point out where i might be wrong.
The recurrence for the problem can be
f(d)=f(d/2)*f(d-d/2)-( f(d/2-1)*f(d-d/2-2) + f(d/2-2)*f(d-d/2-1) )
f(0)=1;f(1)=10;f(2)=100;f(3)=999;
here, f(i) is the total number special digits that can be formed considering that '0' can occur as the first digit. So, the actual answer for a 'd' digit number would be 9*f(d-1).
You can easily memoize the recurrence solution to make a DP solution.
I haven't tried out the validity of this solution, so it might be wrong.
Here is my logic:
for f(d), divide/partition the number into d/2 and (d-d/2) digit numbers, add the product of f(d)*f(d-d/2). Now, to remove the invalid cases which may occur across the partition we made, subtract f(d/2-1)*f(d-d/2-2) + f(d/2-2)*f(d-d/2-1) from the answer (assume that three zero occur across the partition we made). Try it with paper and pen and you will get it.