This submission is migrated from previous version of oj.uz, which used different machine for grading. This submission may have different result if resubmitted.
#include "encoder.h"
#include "encoderlib.h"
#include <iostream>
#include <vector>
using namespace std;
#define lli long long
#define MAXN 22
lli dp[MAXN][MAXN];
void llena_tabla(){
// Voy a llenar la tabla dinámica de caminos desde el final (16, 20) hacia el inicio (0,0).
// es una tabla dinámica normal en que te puedes mover a la izquierda y abajo en este caso.
// La inicialización es que la fila de arriba y la columna de la derecha sólo tienen un camino.
for(int fil = 0; fil <= 16; ++fil) dp[fil][20] = 1;
for(int col = 0; col <= 20; ++col) dp[16][col] = 1;
// Luego hay que llenar la tabla
// Los lugares van de 0 a 20 porque voy a dividir en grupos de 4 números entonces puedo enviar 20 pericos por cada grupo.
for(int col = 19; col >= 0; --col){
// Las filas representan los valores, van del 0 al 16 porque el 0 significa que no esta y luego son los valores de 0 a 15
// uso solo valores de 0 a 15 porque voy a usar 4 bits para indicar el grupo al que pertenece el número y
// 4 bits para el valor en sí, entonces sólo podré poner valores de 0 a 15.
for(int fil = 15; fil >= 0; --fil){
dp[fil][col] = dp[fil + 1][col] + dp[fil][col + 1];
}
}
}
vector<int> construye_secuencia(lli grupo, lli cuatroNumeros){
int valor = 0; // Esta variable lleva el número de la secuencia.
int fil = 0, col = 0; // Llevan la posición en la tabla dinámica.
vector<int> res;
// Para construir la secuencia será necesario fijarse en la tabla de caminos.
// Si moviéndose a la derecha hay suficientes caminos para llegar al número que se requiere,
// entonces hay que moverse a la derecha. En caso contrario hay que moverse hacia arriba (avanzando un valor)
// y tomando en cuenta todas las opciones que se hubieran usado si se movia a la derecha.
while (fil < 16 || col < 20){
if (dp[fil][col + 1] >= cuatroNumeros){ // Hay suficientes opciones sin avanzar de numero
col++;
if (fil) res.push_back((grupo << 4) + fil - 1);
}
else{ // No hay suficientes caminos avanzando a la derecha, hay que aumentar de número
cuatroNumeros -= dp[fil][col + 1];
fil++;
}
}
return res;
}
void encode(int N, int M[])
{
// Construye la tabla de caminos
llena_tabla();
// Haz grupos de 4 números
lli cuatroNumeros;
lli grupo = 0, pos = 0;
while (pos < N){
cuatroNumeros = 0;
for(int i = 0; i <= 3; ++i){
cuatroNumeros <<= 8; // recorrelo 8 lugares para hacer lugar al nuevo
if (pos < N) cuatroNumeros += M[pos++]; // agregale el nuevo número e incrementa la posición.
}
// construye la secuencia y enviala
vector<int> secuencia = construye_secuencia(grupo, cuatroNumeros + 1);
for(auto s : secuencia) send(s);
++grupo; // avanza al siguiente grupo.
}
}
#include "decoder.h"
#include "decoderlib.h"
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
#define lli long long
#define MAXN 22
lli dp_dec[MAXN][MAXN];
void llena_tabla_dec(){
for(int fil = 0; fil <= 16; ++fil) dp_dec[fil][20] = 1;
for(int col = 0; col <= 20; ++col) dp_dec[16][col] = 1;
for(int col = 19; col >= 0; --col)
for(int fil = 15; fil >= 0; --fil)
dp_dec[fil][col] = dp_dec[fil + 1][col] + dp_dec[fil][col + 1];
}
lli construye_numero(vector<int> &secuencia){
int fil = 0, col = 0; // Llevan la posición en la tabla dinámica.
lli res = 0;
// Primero hay que normalizar la secuencia. Hay que sumarle 1 a cada número para
// que estén en el rango [1, 16] y agregarle 0's si le faltan posiciones.
for(int i = 0; i < secuencia.size(); ++i) secuencia[i]++;
while (secuencia.size() < 20) secuencia.push_back(0);
// Después hay que ordenar la secuencia
sort(secuencia.begin(), secuencia.end());
// Finalmente, para reconstruir el número a partir de la secuencia de nuevo se usa
// la tabla dinámica pero esta vez sumando los caminos que se van dejando sin usar.
lli valorprev = 0; // Esta variable es para saber si cambia el valor.
for(int i = 0; i < 20; ++i){
if (secuencia[i] != valorprev){
while (fil < secuencia[i]) {
res += dp_dec[fil][col + 1];
++fil;
}
valorprev = secuencia[i];
}
++col;
}
return res;
}
void decode(int N, int L, int X[])
{
llena_tabla_dec();
vector<int> mensaje;
vector<vector<int> > secuencia(16);
lli grupo, valor, pos;
// Para cada perico del mensaje obten el valor y el grupo al que pertenece.
// Agrega el valor a la secuencia de ese grupo para luego ordenar y reconstruir.
for(int i = 0; i < L; ++i){
grupo = X[i] >> 4;
valor = X[i] & 15;
secuencia[grupo].push_back(valor);
}
// Decodifica cada secuencia para generar los números
lli cuatroNumeros;
pos = 0;
for(int i = 0; i < 16; ++i){
cuatroNumeros = construye_numero(secuencia[i]);
for(int j = 0; j <= 3; ++j) if (pos < N){
mensaje.push_back((cuatroNumeros & 0xFF000000) >> 24); // Escribe el último número
cuatroNumeros <<= 8; // recorre el numero para el siguiente byte.
++pos;
}
if (pos >= N) break;
}
for(auto n : mensaje) output(n);
}
Compilation message (stderr)
encoder.cpp: In function 'std::vector<int> construye_secuencia(long long int, long long int)':
encoder.cpp:34:9: warning: unused variable 'valor' [-Wunused-variable]
34 | int valor = 0; // Esta variable lleva el número de la secuencia.
| ^~~~~
decoder.cpp: In function 'long long int construye_numero(std::vector<int>&)':
decoder.cpp:29:22: warning: comparison of integer expressions of different signedness: 'int' and 'std::vector<int>::size_type' {aka 'long unsigned int'} [-Wsign-compare]
29 | for(int i = 0; i < secuencia.size(); ++i) secuencia[i]++;
| ~~^~~~~~~~~~~~~~~~~~
# | Verdict | Execution time | Memory | Grader output |
---|
Fetching results... |
# | Verdict | Execution time | Memory | Grader output |
---|
Fetching results... |
# | Verdict | Execution time | Memory | Grader output |
---|
Fetching results... |
# | Verdict | Execution time | Memory | Grader output |
---|
Fetching results... |
# | Verdict | Execution time | Memory | Grader output |
---|
Fetching results... |