Cuente números en un rango con una suma de dígitos divisible por K que tenga un primer y último dígito diferentes

Dado un rango en la forma de L y R , y un valor K , la tarea es contar los números entre el rango L a R tal que la suma del dígito sea divisible por K , y el primer dígito no sea igual al último dígito del número. 

Ejemplos: 

Entrada: L = 1, R = 10, K = 2 
Salida:
Explicación: 
Los números de entrada cuya suma de dígitos es divisible por 2 (K = 2) son 2, 4, 6, 8 pero el primer dígito de todos estos números es igual a la última cifra. Por lo tanto, la respuesta es 0, lo que significa que ninguno de los dígitos cumple la condición.

Entrada: L = 10, R = 20, K = 2 
Salida:
Explicación: 
Los números cuya suma de dígitos es divisible por 2 (K = 2) son 11, 13, 15, 17, 19 y 20. Pero en 11 el primer dígito coincide con el último dígito. Así que excluyendo esto, la respuesta será 5. 

Enfoque ingenuo:
el enfoque ingenuo para resolver este problema es verificar cada número si cumple o no la condición dada. Sin embargo, esta solución funcionará de manera ineficiente debido al rango de números. 

Enfoque eficiente:
la idea principal para resolver este problema es utilizar la programación dinámica de dígitos
Hay varios estados que deben definirse para la transición. Entonces, podemos definir los estados de DP como:  

  1. Dado que en digit DP, pensamos que un número es una secuencia de dígitos , por lo que para atravesar la secuencia, necesitamos la posición como estado. Lo que generalmente hacemos es colocar todos los dígitos posibles [0, 9] en la llamada recursiva, que podemos colocar en cada posición para encontrar una posible solución siempre que se cumplan todas las condiciones.
  2. Lo segundo que necesitamos es la suma, con la que hemos construido nuestra secuencia. Dado que la suma puede ser grande, podemos mantener la suma como suma módulo K para una mejor complejidad de espacio y tiempo. Entonces la suma es el segundo estado DP.
  3. Lo tercero que necesitamos es el dígito , que hemos colocado en la primera posición . Mientras colocamos el último dígito de la secuencia, debemos verificar si es igual al primer dígito, que hemos colocado anteriormente o no. Entonces, este será el tercer estado de DP.
  4. El problema es que cada vez que creamos una secuencia de N dígitos, donde N es el número de dígitos presentes en el límite superior del número, no crea 1 si (N=3), pero crea 001. Aquí el el primer dígito es 0 y el último dígito es 1, pero esto es incorrecto ya que hemos creado un número de un solo dígito cuyo primer dígito es igual al último dígito. Entonces, tenemos que verificar esto cada vez en la llamada recursiva. Supongamos que tenemos que construir una secuencia como 0002 donde necesitamos actualizar nuestro dígito inicial igual a 2. Por lo tanto, se debe ignorar un prefijo de ceros. Para verificar esto, necesitamos un nuevo estado booleano (0 o 1) . Este es el cuarto estado DP.
  5. Lo último que necesitamos es verificar si el número que estamos construyendo no excede el límite superior . Supongamos que estamos construyendo un número menor que igual a 456. Hemos creado una secuencia como 45, por lo que en el tercer lugar, no podemos poner ningún dígito entre 0 y 9. Aquí solo podemos colocar números del 0 al 6. Entonces, para verificar este límite, necesitamos un estado booleano adicional . Este es nuestro último estado DP.

Algoritmo: 

  • En cada posición, calculamos la suma de dígitos y eliminamos el prefijo de ceros.
  • El primer dígito distinto de cero será nuestro dígito inicial de la secuencia.
  • En la última posición, comprobaremos si coincide con el dígito inicial o no.

A continuación se muestra la implementación del enfoque anterior. 

C++

// C++ Program to count numbers
// in a range with digit sum
// divisible by K having first
// and last digit different
 
#include <bits/stdc++.h>
using namespace std;
#define ll long long int
 
ll K;
ll N;
vector<int> v;
ll dp[20][1000][10][2][2];
 
void init(ll x)
{
    memset(dp, -1, sizeof(dp));
 
    // For calculating the upper
    // bound of the sequence.
    v.clear();
    while (x > 0) {
        v.push_back(x % 10);
        x /= 10;
    }
 
    reverse(v.begin(), v.end());
 
    N = v.size();
}
 
ll fun(ll pos, ll sum, ll st, ll check, ll f)
{
    if (pos == N) {
 
        // checking whether the sum
        // of digits = 0 or not
        // and the corner case
        // as number equal to 1
        return (sum == 0
                and check == 1);
    }
 
    // If the state is visited
    // then return the answer
    // of this state directly.
    if (dp[pos][sum][st][check][f] != -1)
        return dp[pos][sum][st][check][f];
 
    ll lmt = 9;
 
    // for checking whether digit
    // to be placed is up to
    // upper bound at the
    // position pos or upto 9
    if (!f)
        lmt = v[pos];
 
    ll ans = 0;
    for (int digit = 0; digit <= lmt; digit++) {
 
        ll nf = f;
 
        // calculating new digit
        // sum modulo k
        ll new_sum = (sum + digit) % K;
 
        ll new_check = check;
        ll new_st = st;
        if (f == 0 and digit < lmt)
            nf = 1;
 
        // check if there is a prefix
        // of 0s and current digit != 0
        if (check == 0 and digit != 0) {
 
            // Then current digit will
            // be the starting digit
            new_st = digit;
 
            // Update the boolean flag
            // that the starting digit
            // has been found
            new_check = 1;
        }
 
        // At n-1, check if current digit
        // and starting digit are the same
        // then no need to calculate this answer.
        if (pos == N - 1
            and new_st == digit)
            continue;
 
        // Else find the answer
        ans += fun(pos + 1,
                   new_sum,
                   new_st,
                   new_check, nf);
    }
 
    return dp[pos][sum][st][check][f] = ans;
}
 
// Function to find the required count
void findCount(int L, int R, int K)
{
 
    // Setting up the upper bound
    init(R);
 
    // calculating F(R)
    ll r_ans = fun(0, 0, 0, 0, 0);
 
    // Setting up the upper bound
    init(L - 1);
 
    // calculating F(L-1)
    ll l_ans = fun(0, 0, 0, 0, 0);
 
    cout << r_ans - l_ans;
}
 
// Driver code
int main()
{
    ll L = 10;
    ll R = 20;
    K = 2;
 
    findCount(L, R, K);
 
    return 0;
}

Java

// Java Program to count numbers
// in a range with digit sum
// divisible by K having first
// and last digit different
import java.util.*;
 
class GFG{
 
static int K;
static int N;
static Vector<Integer> v = new Vector<>();
static int [][][][][]dp = new int[20][1000][10][2][2];
 
static void init(int x)
{
    for(int i = 0; i < 20; i++)
        for(int j = 0; j < 1000; j++)
            for(int k = 0; k < 10; k++)
                for(int l = 0; l < 2; l++)
                    for(int m = 0; m < 2; m++)
                        dp[i][j][k][l][m] = -1;
 
    // For calculating the upper
    // bound of the sequence.
    v.clear();
    while (x > 0)
    {
        v.add(x % 10);
        x /= 10;
    }
    Collections.reverse(v);
    N = v.size();
}
 
static int fun(int pos, int sum,
               int st, int check, int f)
{
    if (pos == N)
    {
 
        // checking whether the sum
        // of digits = 0 or not
        // and the corner case
        // as number equal to 1
        return (sum == 0 && check == 1) ? 1 : 0;
    }
 
    // If the state is visited
    // then return the answer
    // of this state directly.
    if (dp[pos][sum][st][check][f] != -1)
        return dp[pos][sum][st][check][f];
 
    int lmt = 9;
 
    // for checking whether digit
    // to be placed is up to
    // upper bound at the
    // position pos or upto 9
    if (f == 0)
        lmt = v.get(pos);
 
    int ans = 0;
    for (int digit = 0; digit <= lmt; digit++)
    {
        int nf = f;
 
        // calculating new digit
        // sum modulo k
        int new_sum = (sum + digit) % K;
 
        int new_check = check;
        int new_st = st;
        if (f == 0 && digit < lmt)
            nf = 1;
 
        // check if there is a prefix
        // of 0s and current digit != 0
        if (check == 0 && digit != 0)
        {
 
            // Then current digit will
            // be the starting digit
            new_st = digit;
 
            // Update the boolean flag
            // that the starting digit
            // has been found
            new_check = 1;
        }
 
        // At n-1, check if current digit
        // and starting digit are the same
        // then no need to calculate this answer.
        if (pos == N - 1 && new_st == digit)
            continue;
 
        // Else find the answer
        ans += fun(pos + 1, new_sum,
                    new_st, new_check, nf);
    }
 
    return dp[pos][sum][st][check][f] = ans;
}
 
// Function to find the required count
static void findCount(int L, int R, int K)
{
 
    // Setting up the upper bound
    init(R);
 
    // calculating F(R)
    int r_ans = fun(0, 0, 0, 0, 0);
 
    // Setting up the upper bound
    init(L - 1);
 
    // calculating F(L-1)
    int l_ans = fun(0, 0, 0, 0, 0);
 
    System.out.print(r_ans - l_ans);
}
 
// Driver code
public static void main(String[] args)
{
    int L = 10;
    int R = 20;
    K = 2;
 
    findCount(L, R, K);
}
}
 
// This code contributed by PrinciRaj1992

Python3

# Python3 program to count numbers
# in a range with digit sum
# divisible by K having first
# and last digit different
K = 0
N = 0
v = []
dp = [[[[[-1 for i in range(2)]
             for j in range(2)]
             for k in range(10)]
             for l in range(1000)]
             for m in range(20)]
 
def init(x):
     
    # For calculating the upper
    # bound of the sequence.
    global K
    global N
    global v
    v = []
     
    while (x > 0):
        v.append(x % 10)
        x //= 10
 
    v = v[::-1]
 
    N = len(v)
 
def fun(pos, sum, st, check, f):
     
    global N
    global v
     
    if (pos == N):
         
        # Checking whether the sum of
        # digits = 0 or not and the
        # corner case as number equal to 1
        return (sum == 0 and check == 1)
 
    # If the state is visited
    # then return the answer
    # of this state directly.
    if (dp[pos][sum][st][check][f] != -1):
        return dp[pos][sum][st][check][f]
 
    lmt = 9
 
    # For checking whether digit to
    # be placed is up to upper bound
    # at the position pos or upto 9
    if (f == False):
        lmt = v[pos]
 
    ans = 0
    for digit in range(lmt + 1):
        nf = f
 
        # Calculating new digit
        # sum modulo k
        new_sum = (sum + digit) % K
 
        new_check = check
        new_st = st
         
        if (f == 0 and digit < lmt):
            nf = 1
 
        # Check if there is a prefix
        # of 0s and current digit != 0
        if (check == 0 and digit != 0):
             
            # Then current digit will
            # be the starting digit
            new_st = digit
 
            # Update the boolean flag
            # that the starting digit
            # has been found
            new_check = 1
 
        # At n-1, check if current digit
        # and starting digit are the same
        # then no need to calculate this answer
        if (pos == N - 1 and new_st == digit):
            continue
 
        # Else find the answer
        ans += fun(pos + 1, new_sum,
                   new_st, new_check, nf)
     
        dp[pos][sum][st][check][f] = ans
 
    return ans
 
# Function to find the required count
def findCount(L, R, K):
     
    # Setting up the upper bound
    init(R)
 
    # calculating F(R)
    r_ans = fun(0, 0, 0, 0, 0)
 
    # Setting up the upper bound
    init(L - 1)
 
    # Calculating F(L-1)
    r_ans = 0
    l_ans = fun(0, 0, 0, 0, 0)
 
    print(l_ans - r_ans)
 
# Driver code
if __name__ == '__main__':
     
    L = 10
    R = 20
    K = 2
 
    findCount(L, R, K)
 
# This code is contributed by Surendra_Gangwar

C#

// C# program to count numbers
// in a range with digit sum
// divisible by K having first
// and last digit different
using System;
using System.Collections.Generic;
 
class GFG{
 
static int K;
static int N;
static List<int> v = new List<int>();
static int [,,,,]dp = new int[20, 1000, 10, 2, 2];
 
static void init(int x)
{
    for(int i = 0; i < 20; i++)
       for(int j = 0; j < 1000; j++)
          for(int k = 0; k < 10; k++)
             for(int l = 0; l < 2; l++)
                for(int m = 0; m < 2; m++)
                   dp[i, j, k, l, m] = -1;
 
    // For calculating the upper
    // bound of the sequence.
    v.Clear();
    while (x > 0)
    {
        v.Add(x % 10);
        x /= 10;
    }
    v.Reverse();
    N = v.Count;
}
 
static int fun(int pos, int sum, int st, 
               int check, int f)
{
    if (pos == N)
    {
 
        // Checking whether the sum
        // of digits = 0 or not
        // and the corner case
        // as number equal to 1
        return (sum == 0 && check == 1) ? 1 : 0;
    }
 
    // If the state is visited
    // then return the answer
    // of this state directly.
    if (dp[pos, sum, st, check, f] != -1)
        return dp[pos, sum, st, check, f];
 
    int lmt = 9;
 
    // For checking whether digit
    // to be placed is up to
    // upper bound at the
    // position pos or upto 9
    if (f == 0)
        lmt = v[pos];
 
    int ans = 0;
    for(int digit = 0; digit <= lmt; digit++)
    {
       int nf = f;
        
       // Calculating new digit
       // sum modulo k
       int new_sum = (sum + digit) % K;
       int new_check = check;
       int new_st = st;
        
       if (f == 0 && digit < lmt)
           nf = 1;
        
       // Check if there is a prefix
       // of 0s and current digit != 0
       if (check == 0 && digit != 0)
       {
            
           // Then current digit will
           // be the starting digit
           new_st = digit;
            
           // Update the bool flag
           // that the starting digit
           // has been found
           new_check = 1;
       }
        
       // At n-1, check if current digit
       // and starting digit are the same
       // then no need to calculate this answer.
       if (pos == N - 1 && new_st == digit)
           continue;
        
       // Else find the answer
       ans += fun(pos + 1, new_sum,
                  new_st, new_check, nf);
    }
    return dp[pos, sum, st, check, f] = ans;
}
 
// Function to find the required count
static void findCount(int L, int R, int K)
{
 
    // Setting up the upper bound
    init(R);
 
    // Calculating F(R)
    int r_ans = fun(0, 0, 0, 0, 0);
 
    // Setting up the upper bound
    init(L - 1);
 
    // calculating F(L-1)
    int l_ans = fun(0, 0, 0, 0, 0);
 
    Console.Write(r_ans - l_ans);
}
 
// Driver code
public static void Main(String[] args)
{
    int L = 10;
    int R = 20;
    K = 2;
 
    findCount(L, R, K);
}
}
 
// This code is contributed by 29AjayKumar

Javascript

<script>
  
// Javascript program to count numbers
// in a range with digit sum
// divisible by K having first
// and last digit different
var K;
var N;
var v = [];
var dp = Array.from(Array(20));
 
function init( x)
{
    for(var i = 0; i< 20;i++)
{
    dp[i] = Array.from(Array(1000),()=>Array(10));
 
    for(var j =0; j<1000;j++)
    {
        for(var k = 0; k<10;k++)
        {
            dp[i][j][k] = Array.from(Array(2), ()=>Array(2).fill(-1));
        }
    }
}
 
    // For calculating the upper
    // bound of the sequence.
    v = [];
    while (x > 0)
    {
        v.push(x % 10);
        x = parseInt(x/10);
    }
    v.reverse();
    N = v.length;
}
 
function fun(pos, sum, st,  check, f)
{
    if (pos == N)
    {
 
        // Checking whether the sum
        // of digits = 0 or not
        // and the corner case
        // as number equal to 1
        return (sum == 0 && check == 1) ? 1 : 0;
    }
 
    // If the state is visited
    // then return the answer
    // of this state directly.
    if (dp[pos][sum][st][check][f] != -1)
        return dp[pos][sum][st][check][f];
 
    var lmt = 9;
 
    // For checking whether digit
    // to be placed is up to
    // upper bound at the
    // position pos or upto 9
    if (f == 0)
        lmt = v[pos];
 
    var ans = 0;
    for(var digit = 0; digit <= lmt; digit++)
    {
       var nf = f;
        
       // Calculating new digit
       // sum modulo k
       var new_sum = (sum + digit) % K;
       var new_check = check;
       var new_st = st;
        
       if (f == 0 && digit < lmt)
           nf = 1;
        
       // Check if there is a prefix
       // of 0s and current digit != 0
       if (check == 0 && digit != 0)
       {
            
           // Then current digit will
           // be the starting digit
           new_st = digit;
            
           // Update the bool flag
           // that the starting digit
           // has been found
           new_check = 1;
       }
        
       // At n-1, check if current digit
       // and starting digit are the same
       // then no need to calculate this answer.
       if (pos == N - 1 && new_st == digit)
           continue;
        
       // Else find the answer
       ans += fun(pos + 1, new_sum,
                  new_st, new_check, nf);
    }
    return dp[pos][sum][st][check][f] = ans;
}
 
// Function to find the required count
function findCount(L, R, K)
{
 
    // Setting up the upper bound
    init(R);
 
    // Calculating F(R)
    var r_ans = fun(0, 0, 0, 0, 0);
 
    // Setting up the upper bound
    init(L - 1);
 
    // calculating F(L-1)
    var l_ans = fun(0, 0, 0, 0, 0);
 
    document.write(r_ans - l_ans);
}
 
// Driver code
var L = 10;
var R = 20;
K = 2;
findCount(L, R, K);
 
// This code is contributed by itsok.
</script>
Producción: 

5

 

Complejidad de tiempo: O(18*1000*10*2*2), que es casi O(2*10^6) .

Espacio auxiliar: O(800*1000)
 

Publicación traducida automáticamente

Artículo escrito por mukul166 y traducido por Barcelona Geeks. The original can be accessed here. Licence: CCBY-SA

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *