Finding optimal substructure - c++

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.

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")

Count amount of 3s in a series of numbers

(This isn't homework)
I'm working on a practice question (https://train.nzoi.org.nz/problems/1207) - "count the number of 3's when printing the numbers from 1 to N". I haven't found any solution online and I was wondering what a more efficient way to answer this question is.
my solution is:
#include <bits/stdc++.h>
using namespace std;
int main()
{
int l;
cin >> l;
int c=0;
for (int i = 0; i < (l + 1); i++)
{
int j = i;
while (j>0)
{
int tmp = j%10;
if (tmp == 3) c++;
j /= 10;
}
}
cout << c << endl;
return 0;
}
although this takes a long time on long numbers.
what is a more efficient way to solve this problem?
EDIT:
For clarification, This is trying to find all instances of 3 while counting from 0 => N
E.G: 13 => 2 occurances of 3
Looks like a good use-case for recursion. Call your function f(n) (short name because I'm going to use math notation below). Then calculate f(n) by something like f(a) + f(b) + ... when all of the numbers a, b, ... are much smaller than n.
I am only going to give ideas by examples, not code. I hope this will be complete enough to write code, and not too much, so the task remains interesting.
First of all:
f(0) = 0
f(1) = 0
f(2) = 0
f(3) = 1
f(4) = 1
...
f(9) = 1
f(10) = 1
Now calculate f(n) for n which are powers of 10:
f(10) = 1
f(100) = 20
f(1000) = 300
...
f(10^(n+1)) = 10 * f(10^n) + 10^n (or something like that)
I hope I did it right. The idea is, for e.g. n = 1000, consider e.g. all 3-digit numbers with first digit 6. There are f(100) 3's in this list. The same for all other first digits, except for 3, where there are 100 more 3's.
Now consider an arbitrary n. Check its first digit; call it d. The list of all numbers smaller than n contains all possible numbers whose first digit is smaller than d, and some numbers whose first digit is exactly d. Now consider all these lists separately, and count 3's in them.
General advice: keep your "slow" code accessible at all times while you are writing your "fast" code. This way, it will be easy to test your code, and find unhandled cases, off-by-one bugs and such.

A problem of taking combination for set theory

Given an array A with size N. Value of a subset of Array A is defined as product of all numbers in that subset. We have to return the product of values of all possible non-empty subsets of array A %(10^9+7).
E.G. array A {3,5}
` Value{3} = 3,
Value{5} = 5,
Value{3,5} = 5*3 = 15
answer = 3*5*15 %(10^9+7).
Can someone explain the mathematics behind the problem. I am thinking of solving it by combination to solve it efficiently.
I have tried using brute force it gives correct answer but it is way too slow.
Next approach is using combination. Now i think that if we take all the sets and multiply all the numbers in those set then we will get the correct answer. Thus i have to find out how many times a number is coming in calculation of answer. In the example 5 and 3 both come 2 times. If we look closely, each number in a will come same number of times.
You're heading in the right direction.
Let x be an element of the given array A. In our final answer, x appears p number of times, where p is equivalent to the number of subsets of A possible that include x.
How to calculate p? Once we have decided that we will definitely include x in our subset, we have two choices for the rest N-1 elements: either include them in set or do not. So, we conclude p = 2^(N-1).
So, each element of A appears exactly 2^(N-1) times in the final product. All remains is to calculate the answer: (a1 * a2 * ... * an)^p. Since the exponent is very large, you can use binary exponentiation for fast calculation.
As Matt Timmermans suggested in comments below, we can obtain our answer without actually calculating p = 2^(N-1). We first calculate the product a1 * a2 * ... * an. Then, we simply square this product n-1 times.
The corresponding code in C++:
int func(vector<int> &a) {
int n = a.size();
int m = 1e9+7;
if(n==0) return 0;
if(n==1) return (m + a[0]%m)%m;
long long ans = 1;
//first calculate ans = (a1*a2*...*an)%m
for(int x:a){
//negative sign does not matter since we're squaring
if(x<0) x *= -1;
x %= m;
ans *= x;
ans %= m;
}
//now calculate ans = [ ans^(2^(n-1)) ]%m
//we do this by squaring ans n-1 times
for(int i=1; i<n; i++){
ans = ans*ans;
ans %= m;
}
return (int)ans;
}
Let,
A={a,b,c}
All possible subset of A is ={{},{a},{b},{c},{a,b},{b,c},{c,a},{a,b,c,d}}
Here number of occurrence of each of the element are 4 times.
So if A={a,b,c,d}, then numbers of occurrence of each of the element will be 2^3.
So if the size of A is n, number of occurrence of eachof the element will be 2^(n-1)
So final result will be = a1^p*a2^pa3^p....*an^p
where p is 2^(n-1)
We need to solve x^2^(n-1) % mod.
We can write x^2^(n-1) % mod as x^(2^(n-1) % phi(mod)) %mod . link
As mod is a prime then phi(mod)=mod-1.
So at first find p= 2^(n-1) %(mod-1).
Then find Ai^p % mod for each of the number and multiply with the final result.
I read the previous answers and I was understanding the process of making sets. So here I am trying to put it in as simple as possible for people so that they can apply it to similar problems.
Let i be an element of array A. Following the approach given in the question, i appears p number of times in final answer.
Now, how do we make different sets. We take sets containing only one element, then sets containing group of two, then group of 3 ..... group of n elements.
Now we want to know for every time when we are making set of certain numbers say group of 3 elements, how many of these sets contain i?
There are n elements so for sets of 3 elements which always contains i, combinations are (n-1)C(3-1) because from n-1 elements we can chose 3-1 elements.
if we do this for every group, p = [ (n-1)C(x-1) ] , m going from 1 to n. Thus, p= 2^(n-1).
Similarly for every element i, p will be same. Thus we get
final answer= A[0]^p *A[1]^p...... A[n]^p

Dynamic Programming: Counting numbers in between

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

How do I add the all digit of an integer until its a single digit number?

If my question was not clear. Here's the whole description:
Consider, n = 653; so I would like to add all the three digit like 6+5+3 = 14.
But it still not an one digit number so I'll again do 1+4 = 5. Now it is as expected how can I do it? The 'n' can hold any integer.
I've searched and found how to separate the digits. Than I started to write the code. But I got stuck. I also found something similar to my question but that wasn't clear to me. I'm not sharing my unsolved code because I want to complete it by myself. But also I am helpless. So It'll will be very helpful if you tell me how can I do that. Sorry, if the question doesn't comfort you.
Do you need the result or the process. If all you care is result, then sum of sum of sum ... of digits can be found as:
int num = 653
int sum = num % 9;
if (sum == 0)
sum = 9;
Okay, strategy is to apply here. How many numbers you need to sum up? In your case 3. Let's see for any number:
int sum = 0;
while( (n / 10) != 0 ) // break if the divsion is zero, meaning number go too small
{
sum += (n%10); // tell me about the rest and sum it
n = n / 10; // reduce n by dividing by ten
}
Now set n = sum and repeat. Yes, with a recursion it would be possible or just add another while loop outside.
If the number is smaller than the divisor itself, in case of integers, you obtain 0. With the modulo operation you get the rest of the division.
Using
sum = num % 9;
Seems to be a faster way to do so.