"Concurso de algoritmos · 300 preguntas rápidas" Una pregunta por día: "Número arcoíris"

" Competencia de algoritmos: 300 preguntas rápidas " se publicará en 2024 y es un libro de ejercicios auxiliar para la "Competencia de algoritmos" .
Todas las preguntas se colocan en el nuevo juez en línea del DO de creación propia .
Los códigos se proporcionan en tres lenguajes: C/C++, Java y Python. Los temas son principalmente temas de nivel medio a bajo y son adecuados para estudiantes principiantes y avanzados.


" Número del arco iris ", enlace: http://oj.ecustacm.cn/problem.php?id=1840

Descripción de la pregunta

[Descripción del título] Número del arco iris: un entero decimal sin 0 inicial, dos números adyacentes son diferentes.
Dados un límite inferior y un límite superior, cuenta el número de arcoíris entre ellos.
[Formato de entrada] La primera línea de entrada es un número entero positivo L, que representa el límite inferior. La segunda línea es un número entero positivo R, que representa el límite superior.
1≤L≤R≤10^(100000). Tenga en cuenta que la longitud del número aquí puede ser de hasta 100.000.
[Formato de salida] Genere un número para representar la respuesta. Dado que la respuesta es demasiado grande, el resto debe ser 998244353.
【Muestra de entrada】

样例11
10

样例212345
65432

【Muestra de salida】

样例110

样例235882

respuesta

  Dado que el rango del intervalo [L, R] es extremadamente grande, la verificación violenta directa de si cada número es un número del arco iris expirará. Además, debido a que el número es demasiado grande, es inconveniente calcularlo directamente por números. Puede procesar números grandes con alta precisión y usar la matriz num [] para almacenar el número grande. num [i] es el i-ésimo dígito del gran número.
  Esta pregunta está relacionada con las estadísticas digitales y es una pregunta del PD relativamente directa sobre estadísticas digitales. El código utiliza la plantilla dfs() de "5.3.2 Implementación de búsqueda de memoria de DP de estadísticas digitales" en "Competencia de algoritmos" [Para conocer los principios y dos métodos de codificación de DP de estadísticas digitales, consulte "Competencia de algoritmos", Tsinghua University Press, Luo Yongjun, escrito por Guo Weibin, páginas 333~338. El código para esta pregunta aplica la plantilla del libro. ], al contar números en dfs(), simplemente excluye el número del arco iris.
  Defina dp[] como el número de números del arco iris con ceros a la izquierda y restricciones de dígitos ilimitadas, por ejemplo:
  dp[1], el número de números del arco iris entre 01~09, dp[1] = 9.
  dp[2], el número de números del arco iris entre 001~099, dp[2] = 81. Excluyendo los números del arco iris 001, 002,..., 009, 011, 022,...099, se excluyen un total de 18 y dp[2] = 99-18 = 81.
  dp[3], el número de números del arco iris dentro de 0001~0999, correspondiente a dp[3] = 729, excluyendo los números del arco iris 0001, 0002, 0099, 0100,…0111, 0112,…, 0999.
  Pasos del código:
  (1) Leer L, R. La línea 28 lee L y R como cadenas.
  (2) solve(s) calcula el número de arcoíris en el rango [1, s], y el número de arcoíris en [L, R] es solve®-solve(L-1). Dado que L es un número expresado en forma de cadena, las líneas 29 a 32 calculan de antemano la forma de cadena de L-1.
  (3) En resolver (s), primero convierta el número grande representado por la cadena s en la matriz num [], y el número grande se almacena en num [1] ~ num [len]. Por ejemplo, si ingresa s = "65432", obtendrá num[1]~num[5] =2, 3, 4, 5, 6.
  (4) dfs () cuenta el número de números del arco iris en [1, s], s es un número grande representado por num [1] ~ num [len]. La línea 13 acumula la cantidad de números sin ceros a la izquierda y la línea 14 elimina los números del arco iris.
  La complejidad se explica a continuación. La tarea principal de dfs () es calcular dp [], es decir, encontrar dp [1] ~ dp [len], la cantidad de cálculo es muy pequeña, aproximadamente 10 × len.
[Puntos clave] Estadísticas digitales DP.

código C ++

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int num[100005];        //存输入的数字
ll dp[100005];
ll MOD = 998244353;
ll dfs(int pos,int last,bool lead,bool limit){
    
                 //last: 上一位
    ll ans = 0;
    if(pos==0)   return 1;                                 //递归到0位数,结束返回
    if(!lead && !limit && dp[pos]!=-1)  return dp[pos];    //记忆化搜索
    int up=(limit ? num[pos] : 9);                         //这一位的最大值
    for(int i=0;i<=up;i++){
    
    
        if(i==0 && lead)   ans += dfs(pos-1,i,true, limit&&(i==up)); //lead=true,无前导0
        else if(last != i) ans += dfs(pos-1,i,false,limit&&(i==up)); //与上一位不同,排除彩虹数
        ans %= MOD;
    }
    if(!lead && !limit)    dp[pos] = ans;    //状态记录:有前导0,无数位限制
    return ans;
}
ll solve(string s){
    
    
    int len=0;
    for(int i=s.length()-1;i>=0;i--)   //把字符串转成数字,存入num[1]~num[len]
        num[++len]=(s[i]-'0');         //例如输入“65432”,得num[1:5]=2 3 4 5 6
    memset(dp,-1,sizeof(dp));
    return dfs(len,-1,true,true);
}
int main(){
    
    
    string L,R;   cin>>L>>R;
    for(int i=L.length()-1;i>=0;i--){
    
        //求L-1,例如L=12345,L-1=12344
        if(L[i]!='0') {
    
     L[i]--; break;}  //这一位不是0,减1即可
        else   L[i]='9';                 //这一位是0,减1得9
    }
    cout<<((solve(R)-solve(L))%MOD + MOD) % MOD;
    return 0;
}

código java

import java.util.*;
public class Main {
    
    
    static long[] dp = new long[100005];
    static int[] num = new int[100005];
    static long MOD = 998244353;
    public static void main(String[] args) {
    
    
        Scanner scanner = new Scanner(System.in);
        String L = scanner.next();
        String R = scanner.next();
        StringBuilder resultL = new StringBuilder(L);
        for (int i = L.length() - 1; i >= 0; i--) {
    
    
            if (resultL.charAt(i) != '0') {
    
    
                resultL.setCharAt(i, (char)(resultL.charAt(i) - 1));
                break;
            } else {
    
    
                resultL.setCharAt(i, '9');
            }
        }
        System.out.println((solve(R) - solve(resultL.toString()) + MOD) % MOD);
    }
    public static long dfs(int pos, int last, boolean lead, boolean limit) {
    
    
        long ans = 0;
        if (pos == 0) return 1;
        if (!lead && !limit && dp[pos] != -1) return dp[pos];
        int up = (limit ? num[pos] : 9);
        for (int i = 0; i <= up; i++) {
    
    
            if (i == 0 && lead) ans += dfs(pos - 1, i, true, limit && (i == up));
            else if (last != i) ans += dfs(pos - 1, i, false, limit && (i == up));
            ans %= MOD;
        }
        if (!lead && !limit) dp[pos] = ans;
        return ans;
    }

    public static long solve(String s) {
    
    
        int len = 0;
        num = new int[100005];
        for (int i = s.length() - 1; i >= 0; i--) 
            num[++len] = s.charAt(i) - '0';
        Arrays.fill(dp, -1);
        return dfs(len, -1, true, true);
    }
}

código pitón

   En solve(s), primero convierta el número grande representado por la cadena s en la matriz num[], y el número grande se almacena en num[0]~num[len-1]. Por ejemplo, si ingresa s = "65432", obtendrá num[0]~num[4] =2, 3, 4, 5, 6.

import sys
sys.setrecursionlimit(100000)
 
MOD = 998244353
dp = [-1] * 100005
num = []
def dfs(pos, last, lead, limit):
    if pos == -1:   return 1     
    global dp
    global num 
    if not lead and not limit and dp[pos] != -1:   return dp[pos]     
    up = num[pos] if limit else 9
    ans = 0     
    for i in range(up + 1):
        if i == 0 and lead:  ans += dfs(pos - 1, i, True,  limit and (i == up))
        elif last != i:      ans += dfs(pos - 1, i, False, limit and (i == up))         
        ans %= MOD     
    if not lead and not limit:    dp[pos] = ans         
    return ans
 
def solve(s):
    global dp
    global num
    num = [int(c) for c in s[::-1]]  #把字符串转成数字,存入num[0]~num[len-1]
    dp = [-1] * 100005
    return dfs(len(num) - 1, -1, True, True)
 
L = input()
R = input()
L_minus_one = str(int(L) - 1)
result = (solve(R) - solve(L_minus_one) + MOD) % MOD
print(result)

Supongo que te gusta

Origin blog.csdn.net/weixin_43914593/article/details/132690816
Recomendado
Clasificación