Given two integers n and x, find the number of ways to express n as the sum of the xth power of unique natural numbers.
Each natural number can be used at most once. Return the total number of ways modulo 109 + 7.
Examples :
Input: n = 10, x = 2
Output: 1
Explanation: 10 = 12 + 32, Hence total 1 possibility.Input: n = 100, x = 2
Output: 3
Explanation: 100 = 102, 62 + 82 and 12 + 32 + 42 + 52 + 72 Hence total 3 possibilities.
Table of Content
Recursive Approach - Exponential Time and O(m) Space:
For each natural number, make two choices: either include its
xth power in the sum or skip it. Recursively continue with the next number and the remaining sum.
- Start with the first natural number
1and the target sumn. - Calculate the
xth power of the current number. - If the power is greater than the remaining sum, stop exploring this branch.
- Otherwise, make two recursive calls: one by including the current power and another by skipping it.
- When the remaining sum becomes
0, return1to count the current combination. - Add the results of both choices and take the result modulo
10^9 + 7.
#include <iostream>
using namespace std;
const int MOD = 1e9 + 7;
int powerX;
// Recursive function to count ways to form n
// using unique powers starting from ind.
int solve(int n, int ind) {
if (n == 0)
return 1;
int power = 1;
// Calculate ind^x
for (int i = 0; i < powerX; i++)
power *= ind;
// Current and all larger powers cannot be used
if (power > n)
return 0;
// Choice 1: Do not take ind^x
int notTake = solve(n, ind + 1);
// Choice 2: Take ind^x
int take = solve(n - power, ind + 1);
return (take + notTake) % MOD;
}
int numOfWays(int n, int x) {
powerX = x;
return solve(n, 1);
}
int main() {
// Input: n = 10, x = 2
// Output: 1
// Explanation: 10 = 1^2 + 3^2
int n = 10, x = 2;
cout << numOfWays(n, x);
return 0;
}
import java.util.*;
class GFG {
static final int MOD = 1000000007;
static int powerX;
// Recursive function to count ways to form n
// using unique powers starting from ind.
static int solve(int n, int ind) {
if (n == 0)
return 1;
int power = 1;
// Calculate ind^x.
for (int i = 0; i < powerX; i++)
power *= ind;
// Current and all larger powers cannot be used.
if (power > n)
return 0;
// Choice 1: Do not take ind^x.
int notTake = solve(n, ind + 1);
// Choice 2: Take ind^x.
int take = solve(n - power, ind + 1);
return (take + notTake) % MOD;
}
static int numOfWays(int n, int x) {
powerX = x;
return solve(n, 1);
}
public static void main(String[] args) {
// Input: n = 10, x = 2
// Output: 1
// Explanation: 10 = 1^2 + 3^2
int n = 10;
int x = 2;
System.out.println(numOfWays(n, x));
}
}
class GFG:
def power(self, num, n):
if n == 0:
return 1
if n % 2 == 0:
half = self.power(num, n // 2)
return half * half
half = self.power(num, n // 2)
return num * half * half
def checkRecursive(self, x, n, curr_num=1, curr_sum=0):
results = 0
# Calculate curr_num^n
p = self.power(curr_num, n)
while p + curr_sum < x:
results += self.checkRecursive(
x,
n,
curr_num + 1,
curr_sum + p
)
curr_num += 1
p = self.power(curr_num, n)
# If sum of powers is equal to x
if p + curr_sum == x:
results += 1
return results
def numOfWays(self, n, x):
return self.checkRecursive(n, x)
using System;
public class GFG
{
const int MOD = 1000000007;
static int powerX;
// Recursive function to count ways to form n
// using unique powers starting from ind.
static int solve(int n, int ind)
{
if (n == 0)
return 1;
int power = 1;
// Calculate ind^x.
for (int i = 0; i < powerX; i++)
power *= ind;
// Current and all larger powers cannot be used.
if (power > n)
return 0;
// Choice 1: Do not take ind^x.
int notTake = solve(n, ind + 1);
// Choice 2: Take ind^x.
int take = solve(n - power, ind + 1);
return (take + notTake) % MOD;
}
static int numOfWays(int n, int x)
{
powerX = x;
return solve(n, 1);
}
public static void Main()
{
// Input: n = 10, x = 2
// Output: 1
// Explanation: 10 = 1^2 + 3^2
int n = 10;
int x = 2;
Console.WriteLine(numOfWays(n, x));
}
}
class Solution {
power(num, n) {
if (n === 0)
return 1;
if (n % 2 === 0) {
const half = this.power(num, Math.floor(n / 2));
return half * half;
}
const half = this.power(num, Math.floor(n / 2));
return num * half * half;
}
checkRecursive(x, n, curr_num = 1, curr_sum = 0) {
let results = 0;
// Calculate curr_num^n
let p = this.power(curr_num, n);
while (p + curr_sum < x) {
results += this.checkRecursive(
x,
n,
curr_num + 1,
curr_sum + p
);
curr_num++;
p = this.power(curr_num, n);
}
// If sum of powers is equal to x
if (p + curr_sum === x)
results++;
return results;
}
numOfWays(n, x) {
return this.checkRecursive(n, x);
}
}
Output
1
Memoization - O(n × m) Time and O(n × m) Space:
The recursive approach repeatedly solves the same subproblems.
To optimize we store the result for each combination of the remaining sum and the current natural number in a DP table.
- Create a DP table where
dp[sum][ind]stores the number of ways to formsumusing numbers fromindonward. - Start the recursion with
sum = nandind = 1. - For every number, calculate its
xth power. - Recursively calculate the number of ways by both skipping and taking the current power.
- Store the result in
dp[sum][ind]to avoid recomputing the same state. - Return the stored value whenever the same state is encountered again.
- Take every result modulo
10^9 + 7.
#include <iostream>
#include <vector>
using namespace std;
const int MOD = 1e9 + 7;
int powerX;
int solve(int n, int ind, vector<vector<int>>& dp) {
if (n == 0)
return 1;
int power = 1;
// Calculate ind^x
for (int i = 0; i < powerX; i++)
power *= ind;
if (power > n)
return 0;
// Return the already computed result
if (dp[n][ind] != -1)
return dp[n][ind];
// Do not take ind^x
int notTake = solve(n, ind + 1, dp);
// Take ind^x
int take = solve(n - power, ind + 1, dp);
return dp[n][ind] = (take + notTake) % MOD;
}
int numOfWays(int n, int x) {
powerX = x;
// Only values up to n are needed as indices.
vector<vector<int>> dp(n + 1, vector<int>(n + 1, -1));
return solve(n, 1, dp);
}
int main() {
// Input: n = 10, x = 2
// Output: 1
// Explanation: 10 = 1^2 + 3^2
int n = 10, x = 2;
cout << numOfWays(n, x);
return 0;
}
import java.util.*;
public class GFG {
static final int MOD = 1000000007;
static int powerX;
static int solve(int n, int ind, int[][] dp) {
if (n == 0)
return 1;
int power = 1;
// Calculate ind^x
for (int i = 0; i < powerX; i++)
power *= ind;
if (power > n)
return 0;
// Return the already computed result
if (dp[n][ind] != -1)
return dp[n][ind];
// Do not take ind^x
int notTake = solve(n, ind + 1, dp);
// Take ind^x
int take = solve(n - power, ind + 1, dp);
return dp[n][ind] = (take + notTake) % MOD;
}
static int numOfWays(int n, int x) {
powerX = x;
int[][] dp = new int[n + 1][n + 1];
for (int i = 0; i <= n; i++)
Arrays.fill(dp[i], -1);
return solve(n, 1, dp);
}
public static void main(String[] args) {
int n = 10, x = 2;
System.out.println(numOfWays(n, x));
}
}
def solve(n, ind, x, dp, mod):
if n == 0:
return 1
power = 1
# Calculate ind^x.
for _ in range(x):
power *= ind
if power > n:
return 0
# Return the already computed result.
if dp[n][ind] != -1:
return dp[n][ind]
# Do not take ind^x.
notTake = solve(n, ind + 1, x, dp, mod)
# Take ind^x.
take = solve(n - power, ind + 1, x, dp, mod)
dp[n][ind] = (take + notTake) % mod
return dp[n][ind]
def numOfWays(n, x):
mod = 10**9 + 7
# Only values up to n are needed as indices.
dp = [[-1] * (n + 1) for _ in range(n + 1)]
return solve(n, 1, x, dp, mod)
if __name__ == "__main__":
# Input: n = 10, x = 2
# Output: 1
# Explanation: 10 = 1^2 + 3^2
n = 10
x = 2
print(numOfWays(n, x))
using System;
public class GFG
{
const int MOD = 1000000007;
static int powerX;
static int solve(int n, int ind, int[,] dp)
{
if (n == 0)
return 1;
int power = 1;
// Calculate ind^x
for (int i = 0; i < powerX; i++)
power *= ind;
if (power > n)
return 0;
// Return the already computed result
if (dp[n, ind] != -1)
return dp[n, ind];
// Do not take ind^x
int notTake = solve(n, ind + 1, dp);
// Take ind^x
int take = solve(n - power, ind + 1, dp);
return dp[n, ind] = (take + notTake) % MOD;
}
static int numOfWays(int n, int x)
{
powerX = x;
int[,] dp = new int[n + 1, n + 1];
for (int i = 0; i <= n; i++)
{
for (int j = 0; j <= n; j++)
dp[i, j] = -1;
}
return solve(n, 1, dp);
}
public static void Main()
{
int n = 10, x = 2;
Console.WriteLine(numOfWays(n, x));
}
}
function solve(n, ind, x, dp, mod) {
if (n === 0)
return 1;
let power = 1;
// Calculate ind^x.
for (let i = 0; i < x; i++)
power *= ind;
if (power > n)
return 0;
// Return the already computed result.
if (dp[n][ind] !== -1)
return dp[n][ind];
// Do not take ind^x.
const notTake = solve(n, ind + 1, x, dp, mod);
// Take ind^x.
const take = solve(n - power, ind + 1, x, dp, mod);
dp[n][ind] = (take + notTake) % mod;
return dp[n][ind];
}
function numOfWays(n, x) {
const mod = 1000000007;
// Only values up to n are needed as indices.
const dp = Array.from(
{ length: n + 1 },
() => new Array(n + 1).fill(-1)
);
return solve(n, 1, x, dp, mod);
}
// Driver Code
const n = 10;
const x = 2;
console.log(numOfWays(n, x));
Output
1
Bottom-Up DP - O(n × m) Time and O(n × m) Space:
The idea is to Convert the recursive decisions into an iterative DP removing the recursion overhead.
- Let
dp[s][i]represent the number of ways to form sumsusing the firstinatural numbers.- For each number, update the table by either excluding or including its
xth power.
- Find the largest natural number
msuch thatm^x <= n. - Create a DP table of size
(n + 1) × (m + 1). - Initialize
dp[0][i] = 1, since there is one way to form sum0: choose nothing. - For every natural number
i, calculatei^x. - For every sum
s, first carry forward the ways that do not usei^x. - If
s >= i^x, add the ways obtained by includingi^x, usingdp[s - i^x][i - 1]. - The final answer is
dp[n][m].
#include <iostream>
#include <vector>
using namespace std;
const int MOD = 1e9 + 7;
int numOfWays(int n, int x) {
int maxNum = 0;
int power = 1;
// Find the largest number whose xth power is <= n
while (true) {
maxNum++;
power = 1;
for (int j = 0; j < x; j++)
power *= maxNum;
if (power > n) {
maxNum--;
break;
}
}
// dp[sum][i] = ways to form sum using numbers 1...i
vector<vector<int>> dp(n + 1, vector<int>(maxNum + 1, 0));
// There is one way to form sum 0: choose nothing.
for (int i = 0; i <= maxNum; i++)
dp[0][i] = 1;
for (int i = 1; i <= maxNum; i++) {
int currPower = 1;
// Calculate i^x
for (int j = 0; j < x; j++)
currPower *= i;
for (int sum = 1; sum <= n; sum++) {
// Do not use i^x
dp[sum][i] = dp[sum][i - 1];
// Use i^x if it does not exceed the current sum
if (sum >= currPower) {
dp[sum][i] =
(dp[sum][i] + dp[sum - currPower][i - 1]) % MOD;
}
}
}
return dp[n][maxNum];
}
int main() {
// Input: n = 10, x = 2
// Output: 1
// Explanation: 10 = 1^2 + 3^2
int n = 10, x = 2;
cout << numOfWays(n, x);
return 0;
}
public class GFG {
static final int MOD = 1000000007;
static int numOfWays(int n, int x) {
int maxNum = 0;
int power = 1;
// Find the largest number whose xth power is <= n
while (true) {
maxNum++;
power = 1;
for (int j = 0; j < x; j++)
power *= maxNum;
if (power > n) {
maxNum--;
break;
}
}
// dp[sum][i] = ways to form sum using numbers 1...i
int[][] dp = new int[n + 1][maxNum + 1];
// There is one way to form sum 0: choose nothing.
for (int i = 0; i <= maxNum; i++)
dp[0][i] = 1;
for (int i = 1; i <= maxNum; i++) {
int currPower = 1;
// Calculate i^x
for (int j = 0; j < x; j++)
currPower *= i;
for (int sum = 1; sum <= n; sum++) {
// Do not use i^x
dp[sum][i] = dp[sum][i - 1];
// Use i^x if it does not exceed the current sum
if (sum >= currPower) {
dp[sum][i] =
(dp[sum][i] + dp[sum - currPower][i - 1]) % MOD;
}
}
}
return dp[n][maxNum];
}
public static void main(String[] args) {
int n = 10, x = 2;
System.out.println(numOfWays(n, x));
}
}
class GFG:
def numOfWays(self, n, x):
MOD = 1000000007
maxNum = 0
power = 1
# Find the largest number whose xth power is <= n
while True:
maxNum += 1
power = 1
for j in range(x):
power *= maxNum
if power > n:
maxNum -= 1
break
# dp[total][i] = ways to form total using numbers 1...i
dp = [[0] * (maxNum + 1) for _ in range(n + 1)]
# One way to form sum 0: choose no numbers.
for i in range(maxNum + 1):
dp[0][i] = 1
for i in range(1, maxNum + 1):
currPower = 1
# Calculate i^x
for j in range(x):
currPower *= i
for total in range(1, n + 1):
# Do not use i^x
dp[total][i] = dp[total][i - 1]
# Use i^x if it does not exceed the current sum
if total >= currPower:
dp[total][i] = (
dp[total][i] +
dp[total - currPower][i - 1]
) % MOD
return dp[n][maxNum]
using System;
public class GFG
{
const int MOD = 1000000007;
static int numOfWays(int n, int x)
{
int maxNum = 0;
int power = 1;
// Find the largest number whose xth power is <= n
while (true)
{
maxNum++;
power = 1;
for (int j = 0; j < x; j++)
power *= maxNum;
if (power > n)
{
maxNum--;
break;
}
}
// dp[sum][i] = ways to form sum using numbers 1...i
int[,] dp = new int[n + 1, maxNum + 1];
// There is one way to form sum 0: choose nothing.
for (int i = 0; i <= maxNum; i++)
dp[0, i] = 1;
for (int i = 1; i <= maxNum; i++)
{
int currPower = 1;
// Calculate i^x
for (int j = 0; j < x; j++)
currPower *= i;
for (int sum = 1; sum <= n; sum++)
{
// Do not use i^x
dp[sum, i] = dp[sum, i - 1];
// Use i^x if it does not exceed the current sum
if (sum >= currPower)
{
dp[sum, i] =
(dp[sum, i] + dp[sum - currPower, i - 1]) % MOD;
}
}
}
return dp[n, maxNum];
}
public static void Main()
{
int n = 10, x = 2;
Console.WriteLine(numOfWays(n, x));
}
}
class GFG {
numOfWays(n, x) {
const MOD = 1000000007;
let maxNum = 0;
let power = 1;
// Find the largest number whose xth power is <= n
while (true) {
maxNum++;
power = 1;
for (let j = 0; j < x; j++)
power *= maxNum;
if (power > n) {
maxNum--;
break;
}
}
// dp[total][i] = ways to form total using numbers 1...i
const dp = Array.from(
{ length: n + 1 },
() => Array(maxNum + 1).fill(0)
);
// There is one way to form sum 0: choose nothing.
for (let i = 0; i <= maxNum; i++)
dp[0][i] = 1;
for (let i = 1; i <= maxNum; i++) {
let currPower = 1;
// Calculate i^x
for (let j = 0; j < x; j++)
currPower *= i;
for (let total = 1; total <= n; total++) {
// Do not use i^x
dp[total][i] = dp[total][i - 1];
// Use i^x if it does not exceed the current sum
if (total >= currPower) {
dp[total][i] =
(dp[total][i] +
dp[total - currPower][i - 1]) % MOD;
}
}
}
return dp[n][maxNum];
}
}
Output
1
Space Optimized DP - O(n × m) Time and O(n) Space :
We can further reduce the space by observing that while processing a number, we only need the results from the previous set of numbers.
- We can maintain a single array where
dp[s]represents the number of ways to form sumsusing the numbers processed so far.- Traverse the sums in reverse order so that each natural number is used at most once.
Follow the below steps to implement the idea:
- Create a one-dimensional array
dpof sizen + 1. - Initialise
dp[0] = 1. - For every natural number
iwhosexth power is at mostn, calculatepower = i^x. - Traverse
sumfromndown topower. - Update
dp[sum]using: dp[sum] += dp[sum - power] - Take the result modulo
10^9 + 7. - The reverse traversal ensures that the same
i^xis not used more than once. - Return
dp[n].
#include <iostream>
#include <vector>
using namespace std;
const int MOD = 1e9 + 7;
int numOfWays(int n, int x) {
vector<int> dp(n + 1, 0);
// One way to form sum 0: choose no numbers.
dp[0] = 1;
for (int num = 1; ; num++) {
int power = 1;
// Calculate num^x
for (int j = 0; j < x; j++)
power *= num;
// No larger number can contribute if num^x > n
if (power > n)
break;
// Traverse backwards so that num^x is used at most once.
for (int sum = n; sum >= power; sum--) {
dp[sum] = (dp[sum] + dp[sum - power]) % MOD;
}
}
return dp[n];
}
int main() {
// Input: n = 10, x = 2
// Output: 1
// Explanation: 10 = 1^2 + 3^2
int n = 10, x = 2;
cout << numOfWays(n, x);
return 0;
}
public class GFG {
static final int MOD = 1000000007;
static int numOfWays(int n, int x) {
int[] dp = new int[n + 1];
// One way to form sum 0: choose no numbers.
dp[0] = 1;
for (int num = 1; ; num++) {
int power = 1;
// Calculate num^x
for (int j = 0; j < x; j++)
power *= num;
// No larger number can contribute if num^x > n
if (power > n)
break;
// Traverse backwards so that num^x is used at most once.
for (int sum = n; sum >= power; sum--) {
dp[sum] = (dp[sum] + dp[sum - power]) % MOD;
}
}
return dp[n];
}
public static void main(String[] args) {
int n = 10, x = 2;
System.out.println(numOfWays(n, x));
}
}
def numOfWays(n, x):
mod = 10**9 + 7
dp = [0] * (n + 1)
# One way to form sum 0: choose no numbers.
dp[0] = 1
num = 1
while True:
power = 1
# Calculate num^x.
for _ in range(x):
power *= num
# No larger number can contribute if num^x > n.
if power > n:
break
# Traverse backwards so that num^x is used at most once.
for total in range(n, power - 1, -1):
dp[total] = (dp[total] + dp[total - power]) % mod
num += 1
return dp[n]
if __name__ == "__main__":
# Input: n = 10, x = 2
# Output: 1
# Explanation: 10 = 1^2 + 3^2
n = 10
x = 2
print(numOfWays(n, x))
using System;
public class GFG
{
const int MOD = 1000000007;
static int numOfWays(int n, int x)
{
int[] dp = new int[n + 1];
// One way to form sum 0: choose no numbers.
dp[0] = 1;
for (int num = 1; ; num++)
{
int power = 1;
// Calculate num^x
for (int j = 0; j < x; j++)
power *= num;
// No larger number can contribute if num^x > n
if (power > n)
break;
// Traverse backwards so that num^x is used at most once.
for (int sum = n; sum >= power; sum--)
{
dp[sum] =
(dp[sum] + dp[sum - power]) % MOD;
}
}
return dp[n];
}
public static void Main()
{
int n = 10, x = 2;
Console.WriteLine(numOfWays(n, x));
}
}
function numOfWays(n, x) {
const mod = 1000000007;
const dp = new Array(n + 1).fill(0);
// One way to form sum 0: choose no numbers.
dp[0] = 1;
let num = 1;
while (true) {
let power = 1;
// Calculate num^x.
for (let i = 0; i < x; i++)
power *= num;
// No larger number can contribute if num^x > n.
if (power > n)
break;
// Traverse backwards so that num^x is used at most once.
for (let total = n; total >= power; total--) {
dp[total] = (dp[total] + dp[total - power]) % mod;
}
num++;
}
return dp[n];
}
function main() {
// Input: n = 10, x = 2
// Output: 1
// Explanation: 10 = 1^2 + 3^2
const n = 10;
const x = 2;
console.log(numOfWays(n, x));
}
main();
Output
1