#include #pragma GCC optimize "-O3" #define endl '\n' #define trace(x) cerr << #x << " = " << x << endl using namespace std; const bool IN_ONLINE_JUDGE = true; const int INF = (int)1e9; const int MAX_COLORS_IN_PALLETE = 16; const int MAX_SIMILARITY_DIFFERENCE = 10; const int NUM_DIRS = 4; const int DIR_X[NUM_DIRS] = {0, -1, 0, 1}; const int DIR_Y[NUM_DIRS] = {-1, 0, 1, 0}; class Color { public: int red; int green; int blue; Color(int red, int green, int blue) { this->red = red; this->green = green; this->blue = blue; } bool operator <(const Color &other) const { return tie(this->red, this->green, this->blue) < tie(other.red, other.green, other.blue); } int operator -(const Color &other) const { int redDifference = this->red - other.red; redDifference *= redDifference; int greenDifference = this->green - other.green; greenDifference *= greenDifference; int blueDifference = this->blue - other.blue; blueDifference *= blueDifference; return redDifference + greenDifference + blueDifference; } int print() const { cout << this->red << ' ' << this->green << ' ' << this->blue; } }; const Color WHITE = Color(255, 255, 255); const Color BLACK = Color(0, 0, 0); const Color RED = Color(255, 0, 0); const Color GREEN = Color(0, 255, 0); const Color BLUE = Color(0, 0, 255); const Color YELLOW = Color(255, 255, 0); const Color MAGENTA = Color(255, 0, 255); const Color CYAN = Color(0, 255, 255); bool isBrightColor(Color color) { return (color - WHITE) <= (color - BLACK); } bool areSimilarColors(Color a, Color b) { return (a - b) <= MAX_COLORS_IN_PALLETE; } bool isNearRed(Color color) { return (color - RED) <= (color - GREEN) && (color - RED) <= (color - BLUE); } bool isNearGreen(Color color) { return (color - GREEN) <= (color - RED) && (color - GREEN) <= (color - BLUE); } bool isNearBlue(Color color) { return (color - BLUE) <= (color - GREEN) && (color - BLUE) <= (color - RED); } bool isNearYellow(Color color) { return isNearRed(color) && isNearGreen(color); } bool isNearMagenta(Color color) { return isNearRed(color) && isNearBlue(color); } bool isNearCyan(Color color) { return isNearBlue(color) && isNearGreen(color); } namespace Compression { int numRows, numCols; vector> picture; ///reads the picture from the input void read() { cin >> numCols >> numRows; picture.reserve(numRows); for (int i = 0; i < numRows; i++) { picture.emplace_back(); picture.reserve(numCols); for (int j = 0; j < numCols; j++) { int red, green, blue; cin >> red >> green >> blue; picture.back().emplace_back(red, green, blue); } } } map numColors; vector> revNumColors; void countColors() { for (int i = 0; i < numRows; i++) { for (int j = 0; j < numCols; j++) { numColors[picture[i][j]]++; } } for (auto &color : numColors) { revNumColors.emplace_back(color.second, color.first); } sort(revNumColors.rbegin(), revNumColors.rend()); } vector pallete; vector usedColors; void setYellowColors() { int ptr = 0; for (int i = 0; i < (int)revNumColors.size() && ptr < 2; i++) { if (isNearYellow(revNumColors[i].second) && !usedColors[i]) { pallete[ptr++] = revNumColors[i].second; usedColors[i] = true; } } } void setMagentaColors() { int ptr = 2; for (int i = 0; i < (int)revNumColors.size() && ptr < 4; i++) { if (isNearMagenta(revNumColors[i].second) && !usedColors[i]) { pallete[ptr++] = revNumColors[i].second; usedColors[i] = true; } } } void setCyanColors() { int ptr = 4; for (int i = 0; i < (int)revNumColors.size() && ptr < 6; i++) { if (isNearCyan(revNumColors[i].second) && !usedColors[i]) { pallete[ptr++] = revNumColors[i].second; usedColors[i] = true; } } } void setRedColors() { int ptr = 6; for (int i = 0; i < (int)revNumColors.size() && ptr < 8; i++) { if (isNearRed(revNumColors[i].second) && !usedColors[i]) { pallete[ptr++] = revNumColors[i].second; usedColors[i] = true; } } } void setGreenColors() { int ptr = 8; for (int i = 0; i < (int)revNumColors.size() && ptr < 10; i++) { if (isNearGreen(revNumColors[i].second) && !usedColors[i]) { pallete[ptr++] = revNumColors[i].second; usedColors[i] = true; } } } void setBlueColors() { int ptr = 10; for (int i = 0; i < (int)revNumColors.size() && ptr < 12; i++) { if (isNearBlue(revNumColors[i].second) && !usedColors[i]) { pallete[ptr++] = revNumColors[i].second; usedColors[i] = true; } } } void setPallete() { pallete.reserve(MAX_COLORS_IN_PALLETE); for (int i = 0; i < MAX_COLORS_IN_PALLETE; i++) { pallete.emplace_back(WHITE); } usedColors.resize(revNumColors.size(), false); setYellowColors(); setMagentaColors(); setCyanColors(); setRedColors(); setGreenColors(); setBlueColors(); int cnt = 0; for (int i = 0; i < (int)revNumColors.size() && cnt < 4; i++) { if (!usedColors[i]) { pallete[15] = revNumColors[i].second; cnt++; } } } ///gets the nearest color to the original color int getSuitableColor(Color color) { int minDifference = INF; int index; for (int i = 0; i < MAX_COLORS_IN_PALLETE; i++) { int difference = color - pallete[i]; if (difference < minDifference) { minDifference = difference; index = i; } } return index; } vector> compressedImage; void compress() { countColors(); setPallete(); ///constructing the compressed image compressedImage.resize(numRows, vector(numCols)); for (int i = 0; i < numRows; i++) { for (int j = 0; j < numCols; j++) { compressedImage[i][j] = getSuitableColor(picture[i][j]); } } } void print() { for (int i = 0; i < MAX_COLORS_IN_PALLETE; i++) { pallete[i].print(); cout << endl; } for (int i = 0; i < numRows; i++) { for (int j = 0; j < numCols; j++) { cout << compressedImage[i][j] << " \n"[j == numCols - 1]; } } } }; namespace Decompression { vector pallete; int numRows, numCols; vector> compressedImage; void read() { pallete.reserve(MAX_COLORS_IN_PALLETE); for (int i = 0; i < MAX_COLORS_IN_PALLETE; i++) { int red, green, blue; cin >> red >> green >> blue; pallete.emplace_back(red, green, blue); } cin >> numCols >> numRows; compressedImage.resize(numRows, vector(numCols)); for (int i = 0; i < numRows; i++) { for (int j = 0; j < numCols; j++) { cin >> compressedImage[i][j]; } } } vector> originalImage; void recover() { originalImage.reserve(numRows); for (int i = 0; i < numRows; i++) { originalImage.emplace_back(); originalImage.back().reserve(numCols); for (int j = 0; j < numCols; j++) { originalImage.back().emplace_back(pallete[compressedImage[i][j]]); } } } void print() { for (int i = 0; i < numRows; i++) { for (int j = 0; j < numCols; j++) { originalImage[i][j].print(); cout << " \n"[j == numCols - 1]; } } } }; void setIO() { ios_base::sync_with_stdio(false); cin.tie(nullptr); cout.tie(nullptr); if (IN_ONLINE_JUDGE) { freopen("imrec.in", "rt", stdin); freopen("imrec.out", "wt", stdout); } } int main() { setIO(); int taskType; cin >> taskType; if (taskType == 0) { Compression::read(); Compression::compress(); Compression::print(); } else { Decompression::read(); Decompression::recover(); Decompression::print(); } return EXIT_SUCCESS;