Permutation and Combination of a given numbers - c++

I want to count the number of combinations we can prouduce of a given number.
For Example M= No. of digits and N=4 Length of a number
M= 3 ({3,7,5}) and N=4
Possible combinations:(The given 3 numbers must be there in the combination)
3577, 3557, 7353 and 5735 and other (32 possible combination)
I found this code on the net. This code is giving me correct output but I can't understand what logic it is using.
Please explain the code below and what its time complexity is.
Thanks in advance.
#define LL long long int
#define sd(x) scanf("%d", &x)
#define MOD 1000000007
#define D double
#define LD long double
#define N 200
LL dp[N][N];
inline void solve(){
int n, m, i, j;
sd(m); sd(n);
memset(dp, 0, sizeof dp);
dp[1][1] = m;
for(i = 1; i < n; i++){
for(j = 1; j <= i && j <= m; j++){
(dp[i + 1][j] += j * dp[i][j]) %= MOD;
(dp[i + 1][j + 1] += (m - j) * dp[i][j]) %= MOD;
}
}
cout<<dp[n][m]<<endl;
}

The dp in the code represent dynamic programming. In many programming contest platforms it stands from state.
Here in the problem:
dp[i][j] represents the number of ways to use j different digits in M to form a number whose length is i. Some requirements: j <= i and j <= M.
So let's assume, we already know a dp[i][j].
Then we can simply calculate dp[i + 1][j] = j * dp[i][j] (one more slot).
As for dp[i + 1][j + 1], it means we have one more slot and M - j choices can be fit in the slot. So dp[i + 1][j + 1] = (M - j) * dp[i][j].
Why M - j? Recall that
j different digits in M
Finally, with these two transition formulas and dp[1][1], we can calculate any dp[i][j] where i <= N and j <= M and j <= i.
Update: example
N = 4, M = 3.
We start by calculating dp[1][1], which is apparently dp[1][1] = 3. There is only one slot and we have M choices. (recall definition of dp)
Then we enter the loop: start from dp[1][1]:
To calculate dp[1 + 1][1]: It means we have two slot and one digits. We have only 1 choice here - use the same digit again. So dp[1 + 1][1] = 1 * dp[1][1] = 3. In your example, dp[2][1] represents {3, 3} {5, 5} {7, 7};
To calculate dp[1 + 1][1 + 1]: it means we have two slots and two different digits, so we have M - 1 choices. So it equals to dp[2][2] = 2 * dp[1][1] = 6. In your example, dp[2][2] represents {3, 5}, {3, 7}, {5, 3}, {5, 7}, {7, 3}, {7, 5}.
Then just follow the loop, we will get to dp[4][3] and it's the answer.

Related

why am i getting slightly off outputs for this dp problem?

The Question:
Given an array A of N distinct integers and an array B of integers(need not be distinct). Find the min no. of numbers that need to be added to B to make A a subsequence of it.
My Strategy:
Quite simple- find the longest common subsequence, lcs and so the answer is sizeof(A) - lcs.
My Code:
int lcs(vector<int>A, vector<int>B, int n, int m)
{
int L[m + 1][n + 1];
int i, j;
/* Following steps build L[m+1][n+1] in
bottom up fashion. Note that L[i][j]
contains length of LCS of X[0..i-1]
and Y[0..j-1] */
for (i = 0; i <= m; i++)
{
for (j = 0; j <= n; j++)
{
if (i == 0 || j == 0)
L[i][j] = 0;
else if (B[i - 1] == A[j - 1])
L[i][j] = L[i - 1][j - 1] + 1;
else
L[i][j] = max(L[i - 1][j], L[i][j - 1]);
}
}
/* L[m][n] contains length of LCS
for A[0..n-1] and B[0..m-1] */
return (n - L[m][n]);
}
My output:
I am getting wrong output. (Differing mostly by 1.) I was also getting TLE for some test cases.
can someone locate where i am going wrong in logic or in code?
If A == [1, 2, 3, 4, 5] and B == [1, 2, 4, 5] then longest common sequence is 2 and your answer is 3, but you only need to add a single number 3 to B to meet the requirements. So the overall logic seems incorrect

How to solve this problem through dynamic programming approach?

I was solving a very basic problem on arrays. The problem statement goes like this:
A basketball court has been opened in SIS, so Demid has decided to hold a basketball exercise session. 2⋅n students have come to Demid's exercise session, and he lined up them into two rows of the same size (there are exactly n people in each row). Students are numbered from 1 to n in each row in order from left to right.
Now Demid wants to choose a team to play basketball. He will choose players from left to right, and the index of each chosen player (excluding the first one taken) will be strictly greater than the index of the previously chosen player. To avoid giving preference to one of the rows, Demid chooses students in such a way that no consecutive chosen students belong to the same row. The first student can be chosen among all 2n students (there are no additional constraints), and a team can consist of any number of students.
Demid thinks, that in order to compose a perfect team, he should choose students in such a way, that the total height of all chosen students is maximum possible. Help Demid to find the maximum possible total height of players in a team he can choose.
For example if the input is:(First line contains the value of n, next 2 rows follow which contains the height of the students)
5
9 3 5 7 3
5 8 1 4 5
My approach was:
#These are global variables and functions.
int arr1[n],arr2[n],sum=0,max=0;
void func1(i)
{
if(i==n)
{
if(sum>max)
max=sum;
return;
}
sum+=arr1[i];
for(k=i+1;k<n;k++)
func2(k);
}
void func2(i)
{
if(i==n)
{
if(sum>max)
max=sum;
return;
}
sum+=arr2[i];
for(k=i+1;k<n;k++)
func1(k);
}
#Caller module. In main
for(i=0;i<n;i++)
{
sum=0;
func1(i);
}
This is my algorithm based on my logical reasoning. I have not coded it yet, will code it later. So feel free to point out any logical errors in the code.
I know this can be solved easily using dynamic programming approach and this algorithm is not quite it. How will the functions look like in that case?
As far as I can point out, the problem in this algorithm is I need to declare arr1 and arr2 globally whereas I get to know the value of n in the main function.
Dynamic programming would be quite straightforward here. We have two choices: Choose from A or skip, Choose from B or skip. Our bottom-up recurrence could look like:
// Choose from A or skip
m[i][0] = max(A[i] + m[i - 1][1], m[i - 1][0])
// Choose from B or skip
m[i][1] = max(B[i] + m[i - 1][0], m[i - 1][1])
JavaScript code:
function f(A, B){
let m = new Array(A.length + 1)
for (let i=0; i<=A.length; i++)
// [a or skip, b or skip]
m[i] = [0, 0]
for (let i=1; i<=A.length; i++){
// Choose from A or skip
m[i][0] = Math.max(
A[i-1] + m[i - 1][1], m[i - 1][0])
// Choose from B or skip
m[i][1] = Math.max(
B[i-1] + m[i - 1][0], m[i - 1][1])
}
return Math.max(...m[A.length])
}
var a = [9, 3, 5, 7, 3]
var b = [5, 8, 1, 4, 5]
console.log(f(a, b))
We can define 2 functions A and B. A(i) is the maximum height we can get by next choosing player with index i or greater from the first row. B(i) is the same for the second row. Now we can write A in terms of B and B in terms of A. For example A(i) is the max over all indices k that are i or greater by choosing the k'th element from the first set plus the max we can get by choosing from k+1 or higher from the second. B(i) is symmetric:
A(i) = max_{k=i..n} a[k] + B(k + 1); A(n) = a[n]
B(i) = max_{k=i..n} b[k] + A(k + 1); B(n) = b[n]
The answer will be max(A(1), B(1)).
A simple way to go is just code this as it's written with 2 memoized functions. I'll use C rather than C++ with tweaking to use 0-based indices.
#include <stdio.h>
#define N 5
int a[] = {9, 3, 5, 7, 3};
int b[] = {5, 8, 1, 4, 5};
int Avals[N], Bvals[N];
int B(int i);
int A(int i) {
if (i >= N) return 0;
if (Avals[i]) return Avals[i];
int max = 0;
for (int k = i; k < N; ++k) {
int val = a[k] + B(k + 1);
if (val > max) max = val;
}
return Avals[i] = max;
}
int B(int i) {
if (i >= N) return 0;
if (Bvals[i]) return Bvals[i];
int max = 0;
for (int k = i; k < N; ++k) {
int val = b[k] + A(k + 1);
if (val > max) max = val;
}
return Bvals[i] = max;
}
int main(void) {
int aMax = A(0);
int bMax = B(0);
printf("%d\n", aMax > bMax ? aMax : bMax);
return 0;
}
I claim there's a way to replace the memoized recursion with simple loops that access the elements of Avals and Bvals in strictly decreasing index order, but I'll let you figure out the details. This result will be smaller, faster code.

Solving T(n) time complexity that contains "variables"

So, I need to find the T(n) and then Big-O (tight upper bound) for the following piece of code:
int sum = 0;
for(int i = 1; i < n; i *= 2) {
for(int j = n; j > 0; j /= 2) {
for(int k = j; k < n; k += 2) {
sum += i + j * k;
}
}
}
Now from what I calculated for the loops, first loop runs log(n) times, second loop runs (log(n) * log(n)) times and the third loop is the one which is causing confusion, because I believe it runs for (n - j)/2 times. My question is can I assume it to be n/2 times, because I think it won't be a tight upper bound if I do that. Or is there a different approach that I am missing?
for(int i = 1; i < n; i *= 2) // (1)
for(int j = n; j > 0; j /= 2) // (2)
for(int k = j; k < n; k += 2) // (3)
For the first iteration of (3) (where k = j = n) no iteration will occur. After j is divided by 2 the third loop will run (n/2)/2 or n/4 times. After the third iteration of (2), (3) will run n/4/2 or n/8 times. We can sum the running time as follows:
n/4 + n/8 + n/16 + ... + n/2^k
This can also be written as:
n * (1/4 + 1/8 + 1/16 + ... + 1/2^k)
Which asymptotically is in O(n).
This is a very interesting question. Let give n a real number and see how it's going. Say, n=100. If we only look at the two inner loops
j k
100 None
50 50, 52, ..., 98
25 25, 27, ..., 99
12 12, 14, ..., 98
6 6, 8, ..., 98
3 3, 5, ..., 99
1 1, 3, ..., 99
As you can see, the complexity of the third loop is actually O(n). Especially when n is a very large number, it will be close to Θ(n)

Find sequence of consecutive numbers which's multiple is N

I have an exercise with an input N and it wants me to find a sequence of consecutive numbers which's multiple is equal to N. Example
Input | Output
60 | 3 5
3*4*5=60
What i have tried
cin>>b;
for (int i = 2; i <=b; ++i)
{
c=1;
for (int j = i; j <=b; ++j)
{
c*=j;
if(c==b){
cout<<i<<" "<<j<<endl;
return 0;
}else if(c>b){
j=b;
}
}
}
Here is a working solution in Python (see end of the post for C++ version):
def seq_with_product(n):
"""Return a sequence of consecutive numbers whose product is n."""
i, curr_prod = 1, 1
max_j = int(n**0.5) + 1 # n**0.5 is square root of n
for j in range(2, max_j + 1):
curr_prod *= j
while curr_prod > n and i < j-1:
curr_prod /= i
i += 1
if curr_prod == n:
return range(i, j+1)
return []
Let i and j be the start and end number in the current sequence. You start from the sequence with the smallest product [1, 2], and check if it is smaller than the given target n. If it is, you want to increase the product, so you include the next number by increasing j. As soon as you get to a product which is larger, you start removing numbers from the product, starting from the smallest (the while loop). If you get the exact product, your answer are the numbers between i and j. So for example, this is how you reach the answer to 60:
[1, 2] # too small, include the next number
[1, 2, 3] # too small, include the next number
[1, 2, 3, 4] # too small, include the next number
[1, 2, 3, 4, 5] # too big, remove the first number
[2, 3, 4, 5] # too big, remove the first number
[3, 4, 5] # found
Note that you don't need to consider numbers greater than the square root of the target number plus one, so you can stop at max_j.
In C++, it would be something like:
int i = 1, curr_prod = 1;
int max_j = sqrt(n) + 1;
for (int j = 2; j <= max_j; j++) {
curr_prod *= j;
while (curr_prod > n && i < j - 1) {
curr_prod /= i;
i += 1;
}
if (curr_prod == n) cout << i << " " << j << endl;
}
Because of this assignment, the inner loop will never terminate if no sequence with the given starting value i is found:
else if (c > b) {
j = b;
}
Instead you should do this:
else if (c > b) {
break;
}
This will terminate the inner loop and check for a sequence with the next start value i+1.
You should also consider the (very common) case that the only sequence contains only one element which is the number N itself.

Compute the complexity of the following Algorithm? [duplicate]

This question already has answers here:
Big O, how do you calculate/approximate it?
(24 answers)
Closed 8 years ago.
Compute the complexity of the following Algorithm?
I have the following code snippet:
i = 1;
while (i < n + 1) {
j = 1;
while (j < n + 1) {
j = j * 2;
}
i = i + 1;
}
plz explain it in detail
I want to know the the steps to solve the problem so I can solve such problems
Since j grows exponentially, the inner loop takes O(log(n)).
Since i grows linearly, the outer loop takes O(n).
Hence the overall complexity is O(n*log(n)).
i = 1;
while(i < n + 1){
j = 1;
While(j < n + 1){
j = j * 2:
}
i = i + 1;
}
outer loop takes O(n) since it increments by constant.
i = 1;
while(i < n + 1){
i = i + 1;
}
inner loop : j = 1, 2, 4, 8, 16, ...., 2^k
j = 2^k (k >= 0)
when will j stops ?
when j == n,
log(2^k) = log(n)
=> k * lg(2) = lg(n) ..... so k = lg(n).
While(j < n + 1){
j = j * 2;
}
so total O(n * lg(n))
You can simply understand outer-loop(with i) because it loops exactly n times. (1, 2, 3, ..., n). But inner-loop(j) is little difficult to understand.
Let's assume that n is 8. How much it loops? Starting with j = 1, it will be increased as exponentially : 1, 2, 4, 8. When j is over 8, loop will be terminated. It loops exactly 4 times. Then we can think general-form of this problem...
Think of that sequence 1, 2, 4, 8, .... If n is 2^k (k is non-negative integer), inner-loop will take k+1 times. (Because 2^(loop-1) = 2^k) Due to the assumption : n = 2^k, we can say that k = lg(n). So we can say inner-loop takes lg(n)+1 times.
When n is not exactly fit to 2^k, it takes one more time. ([lg(n)]+1) It's not a big deal with complexity though it has floor function. You can ingonre it this time.
So the total costs will be like this : n*(lg(n)+1). If you are familiar with Big-O notation, it can be expressed as : O(n lg n).
This one is similar to the following code :
for( int i = 1;i < n+1 ; i++){ // this loop runs n times
for(int j = 1 ; j<n+1 ; j=j*2){// this loop runs log_2(n)(log base 2 because it grows exponentially with 2)
//body
}
}
Hence in Big-Oh notation it is O(n)*O(logn) ; i.e, O(n*logn)
You can proceed like the following: