题目:
给你两个 正 整数 n 和 x 。
请你返回将 n 表示成一些 互不相同 正整数的 x 次幂之和的方案数。换句话说,你需要返回互不相同整数 [n1, n2, ..., nk] 的集合数目,满足:
由于答案可能非常大,请你将它对 10^9 + 7 取余后返回。
比方说,n = 160 且 x = 3 ,一个表示 n 的方法是 n = 2^3 + 3^3 + 5^3 。
示例 1:
输入:n = 10, x = 2
输出:1
解释:我们可以将 n 表示为:n = 3^2 + 1^2 = 10 。
这是唯一将 10 表达成不同整数 2 次方之和的方案。
示例 2:
输入:n = 4, x = 1
输出:2
解释:我们可以将 n 按以下方案表示:
- n = 4^1 = 4 。
- n = 3^1 + 1^1 = 4 。
提示:
1 <= n <= 300
1 <= x <= 5
分析:
将n看成背包容量,将选中的数字看成价值,就变成了选择不同价值的物品将背包装满的方案数,即0-1背包问题; 动态规划一般分为3步走:
-
确定dp数组含义: 设 dp[j] 表示使用若干个互不相同的数,其 x 次幂的和为 j 的方案数。
-
状态转移方程: 实际计算时,可以倒序从大到小枚举 j,当尝试加入数字 i 时,此时可得到如下推论:
-
如果满足 时,则 dp[j] 保持不变;
-
如果满足 时, ;
-
-
初始化:
dp[0] = 1这是一种常见技巧,用来触发起点计数,此处其含义就是总和为0的方案数为1。
依次计算并返回 dp[n] 即为答案。
AC代码:
class Solution {
public:
int numberOfWays(int n, int x) {
vector<long long> dp(n+1);
dp[0] = 1;
for (int i = 1; pow(i, x) <= n; i++) {
int v = pow(i, x);
for (int j = n; j >= v; j--) {
dp[j] += dp[j - v];
}
}
return dp[n] % 1'000'000'007;
}
};