Open In App

CSES Solutions – Coin Combinations II

Last Updated : 02 Apr, 2024
Improve
Improve
Like Article
Like
Save
Share
Report

Consider a money system consisting of N coins. Each coin has a positive integer value. Your task is to calculate the number of distinct ordered ways you can produce a money sum X using the available coins.

Examples:

Input: N = 3, X = 9, coins[] = {2, 3, 5}
Output: 3
Explanation: There are three ways to produce money sum of 9.

  • Coins {2, 2, 5}, sum = 2 + 2 + 5 = 9.
  • Coins {3, 3, 3}, sum = 3 + 3 + 3 = 9.
  • Coins {2, 2, 2, 3}, sum = 2 + 2 + 2 + 3 = 9.

Input: N = 2, X = 4, coins[] = {1, 2}
Output: 3
Explanation: There are three ways to produce money sum of 4.

  • Coins {1, 1, 1, 1}, sum = 1 + 1 + 1 + 1 = 4.
  • Coins {1, 1, 2}, sum = 1 + 1 + 2 = 4.
  • Coins {2, 2}, sum = 2 + 2 = 4.

Approach: To solve the problem, follow the below idea:

The problem is similar to Coin Combinations I but in this problem, we need to find the number of distinct ordered ways to produce sum X. This means that all rearrangements of coins are counted as one way only, for example: coins {1, 1, 2} is same as coins {1, 2, 1}. We can solve the problem using Dynamic Programming. Maintain a dp[] array such that dp[i] stores the number of ordered ways to construct sum i.

In order to avoid counting two ways having same coins with different order, we will choose only one coin at a time and find the number of ways to construct sums from 0 to X using any number of that coin only. In other words, we will choose the first coin and find the number of ways to construct sum from 0 to X using the first coin any number of times. Then, we choose the second coin, and find the number of ways to construct sum from 0 to X by first picking any number(possibly 0) of first coin, then picking any number of second coin. Then, we choose the third coin, and find the number of ways to construct sum from 0 to X by first picking any number(possibly 0) of first coin, then picking any number(possibly 0) of second coin and any number of third coin. In this way, we have fixed the order of coins from first to last to avoid counting two ways with same coins but different order.

Step-by-step algorithm:

  • Maintain dp[] array such that dp[i] stores the number of ordered ways to construct sum i.
  • Initialize dp[0] = 0 as there is only one way to construct sum 0 that is to not choose any coin.
  • Iterate over all coins from 0 to N – 1.
    • Iterate over all sums j from coins[i] to X
      • Add the number of ways to construct sum (j – coins[i]) to dp[j].
  • After iterating over all the sums for all coins, return dp[X] as the final answer.

Below is the implementation of the algorithm:

C++
#include <bits/stdc++.h>
#define ll long long int
#define mod 1000000007
using namespace std;

// function to find the number of distinct ordered ways to
// produce a money sum X using coins[]
ll solve(ll N, ll X, vector<ll>& coins)
{
    // dp[] array such that dp[i] stores the number of
    // ordered ways to construct sum i
    vector<ll> dp(X + 1, 0);

    // Initialize dp[0] = 0 as there is only one way to
    // construct sum 0 that is to not choose any coin
    dp[0] = 1;

    // Iterate over all coins from 0 to N - 1
    for (int i = 0; i < N; i++) {
        // Iterate over all sums j from coins[i] to X
        for (int j = coins[i]; j <= X; j++) {
            // Add the number of ways to construct sum (j -
            // coins[i]) to dp[j]
            dp[j] = (dp[j] + dp[j - coins[i]]) % mod;
        }
    }

    // Return the number of ordered ways to construct sum X
    return dp[X];
}

int main()
{
    // Sample Input
    ll N = 3, X = 9;
    vector<ll> coins = { 2, 3, 5 };

    cout << solve(N, X, coins);
}
Java
import java.util.Arrays;
import java.util.List;

public class Main {
    static final long MOD = 1000000007;

    // Function to find the number of distinct ordered ways to
    // produce a money sum X using coins
    static long solve(int N, int X, List<Long> coins) {
        // dp[] array such that dp[i] stores the number of
        // ordered ways to construct sum i
        long[] dp = new long[X + 1];
        Arrays.fill(dp, 0);

        // Initialize dp[0] = 1 as there is only one way to
        // construct sum 0 that is to not choose any coin
        dp[0] = 1;

        // Iterate over all coins from 0 to N - 1
        for (int i = 0; i < N; i++) {
            // Iterate over all sums j from coins[i] to X
            for (int j = coins.get(i).intValue(); j <= X; j++) {
                // Add the number of ways to construct sum (j -
                // coins[i]) to dp[j]
                dp[j] = (dp[j] + dp[j - coins.get(i).intValue()]) % MOD;
            }
        }

        // Return the number of ordered ways to construct sum X
        return dp[X];
    }

    public static void main(String[] args) {
        // Sample Input
        int N = 3, X = 9;
        List<Long> coins = Arrays.asList(2L, 3L, 5L);

        System.out.println(solve(N, X, coins));
    }
}


// This code is contributed by shivamgupta310570
C#
using System;
using System.Collections.Generic;

class MainClass {
    static readonly long MOD = 1000000007;

    // Function to find the number of distinct ordered ways to
    // produce a money sum X using coins
    static long Solve(int N, int X, List<long> coins) {
        // dp[] array such that dp[i] stores the number of
        // ordered ways to construct sum i
        long[] dp = new long[X + 1];
        Array.Fill(dp, 0);

        // Initialize dp[0] = 1 as there is only one way to
        // construct sum 0 that is to not choose any coin
        dp[0] = 1;

        // Iterate over all coins from 0 to N - 1
        for (int i = 0; i < N; i++) {
            // Iterate over all sums j from coins[i] to X
            for (int j = (int)coins[i]; j <= X; j++) {
                // Add the number of ways to construct sum (j -
                // coins[i]) to dp[j]
                dp[j] = (dp[j] + dp[j - (int)coins[i]]) % MOD;
            }
        }

        // Return the number of ordered ways to construct sum X
        return dp[X];
    }

    public static void Main (string[] args) {
        // Sample Input
        int N = 3, X = 9;
        List<long> coins = new List<long> {2, 3, 5};

        Console.WriteLine(Solve(N, X, coins));
    }
}
Javascript
function solve(N, X, coins) {
    const MOD = 1000000007;
    // dp[] array such that dp[i] stores the number of
    // ordered ways to the construct sum i
    let dp = new Array(X + 1).fill(0);
    dp[0] = 1;
    // Iterate over all coins from 0 to N - 1
    for (let i = 0; i < N; i++) {
        // Iterate over all sums j from the coins[i] to X
        for (let j = coins[i]; j <= X; j++) {
            dp[j] = (dp[j] + dp[j - coins[i]]) % MOD;
        }
    }
    return dp[X];
}
// Sample Input
const N = 3;
const X = 9;
const coins = [2, 3, 5];
console.log(solve(N, X, coins));
Python3
# Function to find the number of distinct ordered ways to
# produce a money sum X using coins
def solve(N, X, coins):
    mod = 1000000007
    
    # dp list such that dp[i] stores the number of
    # ordered ways to construct sum i
    dp = [0] * (X + 1)
    
    # Initialize dp[0] = 1 as there is only one way to
    # construct sum 0 that is to not choose any coin
    dp[0] = 1
    
    # Iterate over all coins
    for coin in coins:
        # Iterate over all sums j from coin to X
        for j in range(coin, X + 1):
            # Add the number of ways to construct sum (j - coin) to dp[j]
            dp[j] = (dp[j] + dp[j - coin]) % mod
    
    # Return the number of ordered ways to construct sum X
    return dp[X]

# Sample Input
N = 3
X = 9
coins = [2, 3, 5]

print(solve(N, X, coins))

Output
3

Time Complexity: O(N * X), where N is the number of coins and X is the sum we need to produce.
Auxiliary Space: O(X)



Like Article
Suggest improvement
Share your thoughts in the comments

Similar Reads