📜  使用动态编程计算数字总和为Y的[L,R]范围内的数字

📅  最后修改于: 2021-04-29 10:36:48             🧑  作者: Mango

先决条件:递归,动态编程,数字DP

给定整数Y和范围[L,R] ,任务是从给定范围中找到总和等于Y的所有数字的计数。
例子:

方法:首先将问题概括为[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)