📜  计算给定范围内的数字,使偶数之和大于奇数之和

📅  最后修改于: 2021-09-22 09:41:01             🧑  作者: Mango

给定两个整数LR,表示范围 [L, R]。任务是找出给定范围 [L,R] 中偶数和大于奇数的总数。

例子:

先决条件:数字DP

方法:
首先,计算所需的数字直至 R,即在 [0, R] 范围内。为了得到 [L, R] 范围内的答案,求解从 0 到 R 的范围,然后减去范围从 0 到 L – 1 的答案。定义 DP 状态如下:

  • 将数字视为一串数字,一个状态是我们当前所处的位置。如果我们处理的数字最大为 10^18,则此位置的值可以从 0 到 18。在每次递归调用中,尝试通过放置 0 到 9 的数字从左到右构建序列。
  • 第一个状态是到目前为止已放置的偶数位数的总和
  • 第二个状态是到目前为止放置的奇数总和
  • 另一种状态是布尔变量tight ,它告诉我们要构建的数字已经变得小于R,因此在即将到来的递归调用中,我们可以放置0到9之间的任何数字。如果数字没有变小,则最大限制我们可以放置的数字是 R 中当前位置的数字。

下面是上述方法的实现:

C++
// C++ code to count number in the range
// having the sum of even digits greater
// than the sum of odd digits
#include 
  
// as the number can be up to 10^18
#define int long long
  
using namespace std;
  
vector v;
  
int dp[18][180][180][2];
  
int memo(int index, int evenSum,
                      int oddSum, int tight)
{
    // Base Case
  
    if (index == v.size()) {
        // check if condition satisfied or not
        if (evenSum > oddSum)
            return 1;
        else
            return 0;
    }
  
    // If this result is already computed
    // simply return it
    if (dp[index][evenSum][oddSum][tight] != -1)
        return dp[index][evenSum][oddSum][tight];
  
    // Maximum limit upto which we can place
    // digit. If tight is 0, means number has
    // already become smaller so we can place
    // any digit, otherwise num[pos]
  
    int limit = (tight) ? v[index] : 9;
  
    int ans = 0;
  
    for (int d = 0; d <= limit; d++) {
        int currTight = 0;
  
        if (d == v[index])
            currTight = tight;
  
        // if current digit is odd
        if (d % 2 != 0)
            ans += memo(index + 1, evenSum,
                        oddSum + d, currTight);
  
        // if current digit is even
        else
            ans += memo(index + 1, evenSum + d,
                        oddSum, currTight);
    }
  
    dp[index][evenSum][oddSum][tight] = ans;
    return ans;
}
// Function to convert n into its
// digit vector and uses memo() function
// to return the required count
int CountNum(int n)
{
    v.clear();
    while (n) {
        v.push_back(n % 10);
        n = n / 10;
    }
  
    reverse(v.begin(), v.end());
  
    // Initialize DP
    memset(dp, -1, sizeof(dp));
    return memo(0, 0, 0, 1);
}
  
// Driver Code
  
int32_t main()
{
    int L, R;
    L = 2;
    R = 10;
    cout << CountNum(R) - CountNum(L - 1) << "\n";
    return 0;
}


Java
// Java code to count number in the range
// having the sum of even digits greater
// than the sum of odd digits
import java.util.*;
  
class GFG
{
  
    static Vector v = new Vector<>();
  
    static int[][][][] dp = new int[18][180][180][2];
  
    static int memo(int index, int evenSum,
    int oddSum, int tight)
    {
        // Base Case
  
        if (index == v.size()) 
        {
            // check if condition satisfied or not
            if (evenSum > oddSum) 
            {
                return 1;
            } 
            else
            {
                return 0;
            }
        }
  
        // If this result is already computed
        // simply return it
        if (dp[index][evenSum][oddSum][tight] != -1) 
        {
            return dp[index][evenSum][oddSum][tight];
        }
  
        // Maximum limit upto which we can place
        // digit. If tight is 0, means number has
        // already become smaller so we can place
        // any digit, otherwise num[pos]
        int limit = (tight > 0) ? v.get(index) : 9;
  
        int ans = 0;
  
        for (int d = 0; d <= limit; d++) 
        {
            int currTight = 0;
  
            if (d == v.get(index)) 
            {
                currTight = tight;
            }
  
            // if current digit is odd
            if (d % 2 != 0) 
            {
                ans += memo(index + 1, evenSum,
                        oddSum + d, currTight);
            } // if current digit is even
            else
            {
                ans += memo(index + 1, evenSum + d,
                        oddSum, currTight);
            }
        }
  
        dp[index][evenSum][oddSum][tight] = ans;
        return ans;
    }
    // Function to convert n into its
    // digit vector and uses memo() function
    // to return the required count
  
    static int CountNum(int n) 
    {
        v.clear();
        while (n > 0) 
        {
            v.add(n % 10);
            n = n / 10;
        }
  
        Collections.reverse(v);
  
        // Initialize DP
        for (int i = 0; i < 18; i++)
        {
            for (int j = 0; j < 180; j++) 
            {
                for (int k = 0; k < 180; k++) 
                {
                    for (int l = 0; l < 2; l++)
                    {
                        dp[i][j][k][l] = -1;
                    }
                }
            }
        }
  
        return memo(0, 0, 0, 1);
    }
  
    // Driver Code
    public static void main(String[] args) 
    {
        int L, R;
        L = 2;
        R = 10;
        System.out.println(CountNum(R) - CountNum(L - 1));
  
    }
}
  
// This code is contributed by Princi Singh


Python3
# Python code to count number in the range
# having the sum of even digits greater
# than the sum of odd digits
  
def memo(index, evenSum, oddSum, tight):
  
    # Base Case
    if index == len(v):
  
        # check if condition satisfied or not
        if evenSum > oddSum:
            return 1
        else:
            return 0
  
    # If this result is already computed
    # simply return it
    if dp[index][evenSum][oddSum][tight] != -1:
        return dp[index][evenSum][oddSum][tight]
  
    # Maximum limit upto which we can place
    # digit. If tight is 0, means number has
    # already become smaller so we can place
    # any digit, otherwise num[index]
    limit = v[index] if tight else 9
  
    ans = 0
  
    for d in range(limit + 1):
        currTight = 0
  
        if d == v[index]:
            currTight = tight
  
        # if current digit is odd
        if d % 2 != 0:
            ans += memo(index + 1, evenSum, 
                        oddSum + d, currTight)
  
        # if current digit is even
        else:
            ans += memo(index + 1, evenSum + d, 
                            oddSum, currTight)
  
    dp[index][evenSum][oddSum][tight] = ans
    return ans
  
# Function to convert n into its digit vector
# and uses memo() function to return the
# required count
def countNum(n):
    global dp, v
  
    v.clear()
    num = []
    while n:
        v.append(n % 10)
        n //= 10
  
    v.reverse()
  
    # Initialize dp
    dp = [[[[-1, -1] for i in range(180)] for j in range(180)]
        for k in range(18)]
    return memo(0, 0, 0, 1)
  
# Driver Code
if __name__ == "__main__":
    dp = []
    v = []
  
    L = 2
    R = 10
    print(countNum(R) - countNum(L - 1))
  
# This code is contributed by
# sanjeev2552


C#
// C# code to count number in the range
// having the sum of even digits greater
// than the sum of odd digits
using System.Collections.Generic;
using System;
  
class GFG
{
  
    static List v = new List();
  
    static int [,,,]dp = new int[18,180,180,2];
  
    static int memo(int index, int evenSum,
    int oddSum, int tight)
    {
        // Base Case
  
        if (index == v.Count) 
        {
            // check if condition satisfied or not
            if (evenSum > oddSum) 
            {
                return 1;
            } 
            else
            {
                return 0;
            }
        }
  
        // If this result is already computed
        // simply return it
        if (dp[index,evenSum,oddSum,tight] != -1) 
        {
            return dp[index,evenSum,oddSum,tight];
        }
  
        // Maximum limit upto which we can place
        // digit. If tight is 0, means number has
        // already become smaller so we can place
        // any digit, otherwise num[pos]
        int limit = (tight > 0) ? v[index] : 9;
  
        int ans = 0;
  
        for (int d = 0; d <= limit; d++) 
        {
            int currTight = 0;
  
            if (d == v[index]) 
            {
                currTight = tight;
            }
  
            // if current digit is odd
            if (d % 2 != 0) 
            {
                ans += memo(index + 1, evenSum,
                        oddSum + d, currTight);
            } // if current digit is even
            else
            {
                ans += memo(index + 1, evenSum + d,
                        oddSum, currTight);
            }
        }
  
        dp[index,evenSum,oddSum,tight] = ans;
        return ans;
    }
      
    // Function to convert n into its
    // digit vector and uses memo() function
    // to return the required count
    static int CountNum(int n) 
    {
        v.Clear();
        while (n > 0) 
        {
            v.Add(n % 10);
            n = n / 10;
        }
  
        v.Reverse();
  
        // Initialize DP
        for (int i = 0; i < 18; i++)
        {
            for (int j = 0; j < 180; j++) 
            {
                for (int k = 0; k < 180; k++) 
                {
                    for (int l = 0; l < 2; l++)
                    {
                        dp[i,j,k,l] = -1;
                    }
                }
            }
        }
  
        return memo(0, 0, 0, 1);
    }
  
    // Driver Code
    public static void Main(String[] args) 
    {
        int L, R;
        L = 2;
        R = 10;
        Console.WriteLine(CountNum(R) - CountNum(L - 1));
  
    }
}
  
/* This code is contributed by PrinciRaj1992 */


输出:
4

时间复杂度:当 0 < a,b < 10 18时,最多有 18*(180)*(180)*2 次计算

如果您希望与专家一起参加现场课程,请参阅DSA 现场工作专业课程学生竞争性编程现场课程