先决条件:递归,动态编程,数字DP
给定整数Y和范围[L,R] ,任务是从给定范围中找到总和等于Y的所有数字的计数。
例子:
Input: L = 0, R = 11, Y = 2
Output: 2
2 -> 2
11 -> 1 + 1 = 2
Input: L = 500, R = 1000, Y = 6
Output: 3
Constraints:
0 <= L <= R <= 10^18
0 <= Y <= 162 (Which is the maximum possible sum a 18 digit number can have)
方法:首先将问题概括为[L,R]可以写为[0,R] – [0,L-1],即首先找到数字总和= Y的范围[0,R]中的所有数字,然后对于范围[0,L-1],最后将每个值相减得出所需的结果。因此,对于数字的情况,让我们将数字L和R的数字存储在2个单独的向量中,以便访问其数字会更加容易。然后,我们需要一个函数来携带(current_index,标志,sum)。此函数是我们逻辑的主要部分。初始化current_index = 0,标志= 0,sum = 0。
假设R = 462,此数字有3个索引,即0、1、2。现在检查可以用多少种方法填充第0个索引。通过观察,我们可以说我们可以将第0个索引填充为0、1、2、3和4。如果我们超过4,那么我们将形成一个大于462的数字。
现在,如果您在第0个索引中插入了0,那么第一个索引有什么可能呢?答案– 0、1、2、3、4、5、6、7、8、9。由于第0个索引中的数字为0,因此您可以在第一个索引中填充0-9之间的任何数字。好的,因为您可以在下一个索引中填充任何数字,所以将打开flag =1。flag = 1告诉我们,我们有优势可以填充0-9之间的任何数字。同样考虑其他索引。
现在,如果我们看到基本条件
if(current_index == n){
if(sum == Y)返回1;
否则返回0;
}
下面是上述方法的实现:
C++
#include
using namespace std;
// function to convert digit to vector
vector digitToVec(int n) {
vector a;
while (n) {
a.push_back(n % 10);
n = n / 10;
}
reverse(a.begin(), a.end());
return a;
}
int Y; // setting Y as global
int dp[19][2][18 * 9 + 1]; // 3D dp
int func(int ind, int flag, int sum, vector a) {
if (ind == a.size()) {
if (sum == Y) return 1;
else return 0;
}
if (dp[ind][flag][sum] != -1) return dp[ind][flag][sum];
// if flag = 0, I know I can only fill from 0 to a[ind]
// if flag = 1, I have the advantage to fill from 0 to 9
int limit = 9;
if (flag == 0) limit = a[ind];
int cnt = 0;
for (int num = 0; num <= limit; num++) {
// if flag = 0, which means no advantage
// and I am still filling the same number as a[ind] means giving him no advantage
// hence the next recursion call flag still stays as 0
if (flag == 0 && num == a[ind]) {
cnt += func(ind + 1, 0, sum + num, a);
}
else {
cnt += func(ind + 1, 1, sum + num, a);
}
}
return dp[ind][flag][sum] = cnt;
}
// intermediate function helping to initialize all values of func()
int ans(int n) {
vector a = digitToVec(n);
memset(dp, -1, sizeof dp); // initializing dp as -1
return func(0, 0, 0, a);
}
// Driver code
int main() {
int l, r;
cin >> l >> r >> Y;
cout << ans(r) - ans(l - 1);
return 0;
}
2
现在说最坏的情况是时间复杂度:O(19 * 2 *(18 * 9)* 10)