Multiple of 2019
Explicación
Para guardar secciones del string, podemos construir un arreglo de sufijos tal que:
Por ejemplo, si nuestro string fuera y el módulo fuera (en lugar de , por simplicidad), el arreglo de sufijos sería
Hay que tener en cuenta que también se considera un sufijo vacío.
Esto es útil porque podemos acceder a cualquier subcadena en mediante una consulta de rango. Así, si y , esto significa o .
También significa que si tanto (ambos sufijos tienen el mismo resto), restar llevaría a , es decir, una subcadena divisible por .
Así, con , . Como restan a cero, la subcadena del índice al da un número divisible por el módulo. (La subcadena es , que es divisible por 3).
Sin embargo, todavía tendríamos que recorrer cada par de sufijos posibles , lo que sería .
En su lugar, no necesitamos saber qué sufijo tiene un cierto resto, sino cuántos sufijos tienen ese resto.
Para detallar, podemos tomar y elegir 2 números divisibles por el mismo resto de 2019, donde la cantidad de veces que ocurre un cierto resto, y 2 (porque elegimos 2 índices y ).
Por lo tanto, nuestra respuesta es el conteo de todos los restos en un arreglo de y .
Así, en nuestro ejemplo con , el nuevo arreglo se vería así:
Donde cada índice representa el conteo de un cierto resto.
- Hay sufijos con resto al dividir por ,
- Hay sufijos con resto al dividir por ,
- Y no hay sufijos con resto
Entonces, la suma de todos estos números sería
Si , debería ser , porque no hay sufijos suficientes para formar un par.
Video de Errichto
Video de YouTube (83yW2Pp6HMk)
Implementación
Complejidad temporal:
#include <iostream>
using namespace std;
int main() {
string s;
cin >> s;
int num = 0, n = s.size(), pow = 1;
// inicializa el arreglo con initializer list
// explicado aquí: https://www.learncpp.com/cpp-tutorial/arrays-part-ii/
int count[2019]{1};
for (int i = n - 1; i >= 0; i--) {
// hallamos el resto del número actual módulo 2019
num = (num + pow * (s[i] - '0')) % 2019;
// incrementamos el conteo de este resto
count[num]++;
pow = pow * 10 % 2019;
}
long long ans = 0;
for (int i = 0; i < 2019; i++) {
// hay nC2 formas de emparejar los números con el mismo resto
ans += (long long)count[i] * (count[i] - 1) / 2;
}
cout << ans << endl;
return 0;
}import java.io.*;
import java.util.*;
public class MultipleOf2019 {
public static void main(String[] args) {
Kattio io = new Kattio();
String numberString = io.next();
int num = 0;
int stringLength = numberString.length();
int pow = 1;
int[] count = new int[2019];
count[0] = 1;
for (int i = stringLength - 1; i >= 0; i--) {
// hallamos el resto del número actual módulo 2019
num = (num + pow * (numberString.charAt(i) - '0')) % 2019;
// incrementamos el conteo de este resto
count[num]++;
pow = pow * 10 % 2019;
}
long answer = 0;
for (int i = 0; i < 2019; i++) {
// hay nC2 formas de emparejar los números con el mismo resto
answer += (long)count[i] * (count[i] - 1) / 2;
}
io.println(answer);
io.close();
}
// CodeSnip{Kattio}
}MOD = 2019
string = input()
count = [0] * MOD
count[0] = 1
cur_num = 0
power = 1
for c in reversed(string):
# hallamos el resto del número actual MOD 2019
cur_num = (int(c) * power + cur_num) % MOD
# aumentamos la potencia de 10
power = (power * 10) % MOD
# aumentamos el conteo de este resto
count[cur_num] += 1
ans = 0
for rep in count:
# cuando el resto i se repite rep veces hay C(rep, 2) pares válidos
ans += (rep * (rep - 1)) // 2
print(ans)