Jeopardized Projects
Explicación
Un detalle que nos empuja en la dirección correcta es que un caso de prueba posible puede tener consultas que piden un solo número concreto, como
100 100Esto motiva un enfoque de suma de prefijos, donde calculamos la respuesta para cada entero posible y respondemos las consultas con un arreglo de sumas de prefijos.
Para contar de verdad el número de arreglos no palindrómicos que suman un entero (al que de ahora en adelante llamaremos ), podemos usar conteo complementario.
Para contar el número total de arreglos que suman , a secas, evaluamos la siguiente sumatoria:
En esta sumatoria, sumamos sobre todas las longitudes posibles del arreglo, y luego usamos estrellas y barras para contar cuántos arreglos de longitud suman . La resta inicial de es para tener en cuenta que todos los elementos deben ser positivos.
Esta expresión se simplifica entonces a
Se aplica el teorema del binomio para simplificar la sumatoria.
Queda contar el número de arreglos palindrómicos que suman . Para esto hay que considerar dos casos: par y impar.
Si es par, entonces es posible tener un arreglo palindrómico de longitud par. Cada mitad debe sumar y, como las dos son básicamente idénticas, hay arreglos palindrómicos posibles de esta forma. Sin embargo, también podemos formar un arreglo de longitud impar tomando primero un número par de y poniéndolo como elemento central. Esto nos da un total de
El del frente es otro caso borde cuando ponemos todo en el medio. Pero de todos modos, ¡observemos que esto se simplifica a ! Bastante elegante, ¿no?
Si es impar, en cambio, no podemos tener un arreglo palindrómico de longitud par. Solo podemos tomar una cantidad impar de y ponerla como centro, lo que nos da
Esto también se simplifica como el anterior, solo que esta vez queda .
Implementación
Complejidad temporal: , donde es el valor máximo de .
MOD = 10**9 + 7
MAX_VAL = 10**5
two_pows = [1]
for _ in range(1, MAX_VAL + 1):
two_pows.append((two_pows[-1] * 2) % MOD)
pref_sums = [0]
for i in range(1, MAX_VAL + 1):
if i % 2 == 0:
nonpal_num = (two_pows[i - 1] - two_pows[i // 2]) % MOD
else:
nonpal_num = (two_pows[i - 1] - two_pows[(i - 1) // 2]) % MOD
pref_sums.append((pref_sums[-1] + nonpal_num) % MOD)
for _ in range(int(input())):
lo, hi = [int(i) for i in input().split()]
print((pref_sums[hi] - pref_sums[lo - 1]) % MOD)#include <bits/stdc++.h>
using namespace std;
const int MOD = 1e9 + 7;
const int MAX_SUM = 1e5;
int mod(long long a) { return (a + MOD) % MOD; }
int main() {
ios_base::sync_with_stdio(false);
cin.tie(nullptr);
vector<int> pow_two;
vector<int> pref;
// definimos potencias de dos hasta el valor máximo de suma para consultarlas después
pow_two.push_back(1);
for (int i = 1; i < MAX_SUM + 1; i++) {
pow_two.push_back((pow_two.back() * 2) % MOD);
}
// cantidad de soluciones de prefijo en cada i
pref.push_back(0);
for (int i = 1; i < MAX_SUM + 1; i++) {
pref.push_back(mod(pref.back() + mod(pow_two[i - 1] - pow_two[i / 2])));
}
int tests = 0;
cin >> tests;
for (int i = 0; i < tests; i++) {
int l, r;
cin >> l >> r;
cout << mod(pref[r] - pref[l - 1]) << "\n";
}
}