目录
题目来源
知识点
- C++头文件 #include <stdlib.h> 中的 system(“color xx”); (改成ASCII的输出后后,用不上哦)
system(“color XX”)函数可用于修改控制台背景及文字颜色。
第一个X是背景颜色,第二个X是前颜色。(都是16进制的单个字符)
在我写的代码中没有指明XX。就是默认的前白后黑了。
注意点
- ‘\xabcdef’ 输出时, '\x’需要进行转义。 即 ‘\\x’。
- 输入中的 #abcdef 中, abcdef是数字或小写字母。
- 在将输出转换为ASCII码时, 要记得将16进制数字符串填充成2位的。在我的代码中,特别要注意 RGB某一个为0的情况!
0分(略了)
20分
0分->20分: 之前以为输入的#abcdef中,abcdef会是数字或大写字母。在网上看了大佬的测试样例才意识到是小写字母。
通过了前 20 分的测试点。 (注意点2)
数据特点:
m <= 10, n <= 10, p = 1, q = 2;
(有点呆的代码。不太了解c++, 无法熟练运用其中的各种便利的技巧。)
#include <iostream>
#include <fstream>
//#include <stdlib.h> // sysytem()
#include <map>
using namespace std;
map<char, int> s2t; // 16转10
map<int, char> t2s; // 10转16
// 16进制字符串转10进制数字
int sixteen2ten(string sixteen) {
int num = 0;
for (char c: sixteen) {
num = num * 16 + s2t[c];
}
return num;
}
// 10进制数字转“\x” + 16进制字符串
string ten2sixteen(int ten) {
string sixteen = "";
int shang = 0, yu = 0;
string invSixteen = ""; // 倒序16进制字符串
while (ten != 0) {
yu = ten % 16;
shang = ten / 16;
ten = shang;
invSixteen.push_back(t2s[yu]);
}
// 将逆序的调整为正序
if (invSixteen.size() == 1) {
sixteen = "0";
}
for (int i = invSixteen.size() - 1; i >= 0; --i) {
sixteen.push_back(invSixteen[i]);
}
return "\\x" + sixteen;
}
int main() {
//ifstream cin("in3.txt");
//system("color"); // 使终端能根据输出进行颜色变换, 现在这个格式的输出不行。
// 初始化
s2t['0'] = 0, s2t['1'] = 1, s2t['2'] = 2, s2t['3'] = 3, s2t['4'] = 4, s2t['5'] = 5, s2t['6'] = 6, s2t['7'] = 7, s2t['8'] = 8, s2t['9'] = 9, s2t['a'] = 10, s2t['b'] = 11, s2t['c'] = 12, s2t['d'] = 13, s2t['e'] = 14, s2t['f'] = 15; // 注意是小写的
//s2t['0'] = 0, s2t['1'] = 1, s2t['2'] = 2, s2t['3'] = 3, s2t['4'] = 4, s2t['5'] = 5, s2t['6'] = 6, s2t['7'] = 7, s2t['8'] = 8, s2t['9'] = 9, s2t['A'] = 10, s2t['B'] = 11, s2t['C'] = 12, s2t['D'] = 13, s2t['E'] = 14, s2t['F'] = 15;
t2s[0] = '0', t2s[1] = '1', t2s[2] = '2', t2s[3] = '3', t2s[4] = '4', t2s[5] = '5', t2s[6] = '6', t2s[7] = '7', t2s[8] = '8', t2s[9] = '9', t2s[10] = 'A', t2s[11] = 'B', t2s[12] = 'C', t2s[13] = 'D', t2s[14] = 'E', t2s[15] = 'F';
int m, n; // 宽、高——列、行
cin>>m>>n;
int p, q; // 每一小块的宽、高——列、行
cin>>p>>q;
// 存储输入 并 填充
string inputStr[n][m]; // 存储输入 , 注意这里是 n行 m列 (有点乱哈)
for (int i = 0; i < n; ++i) { // 高
for (int j = 0; j < m; ++j) { // 宽
string tmp, t;
cin>>tmp;
if (tmp.size() == 2) { // #a -> #aaaaaa
t = tmp;
for (int ii = 0; ii < 5; ++ii) {
t.push_back(tmp[1]);
}
}
else if (tmp.size() == 4) { // #abc -> #aabbcc
t = "#";
for (int ii = 1; ii <= 3; ++ii) {
t.push_back(tmp[ii]);
t.push_back(tmp[ii]);
}
}
else { // #abcdef
t = tmp;
}
//cout<<"i: "<<i<<" j: "<<j<<" t: "<<t<<endl;
inputStr[i][j] = t;
}
}
//cout<<"OK"<<endl;
int M = n / q, N = m / p; // M行N列的色块
int myRGB[M][N][3]; // 记录每一块的RGB平均值
//cout<<M<<" "<<N<<endl;
// 对每个色块中的像素取平均值
for (int i = 0; i < M; ++i) {
for (int j = 0; j < N; ++j) {
// get每个色块的像素
int sumR, sumG, sumB;
sumR = sumG = sumB = 0;
//cout<<i<<" "<<j<<endl;
for (int ii = i * q; ii < i * q + q; ++ii) {
for (int jj = j * p; jj < j * p + p; ++jj) {
string cur = inputStr[ii][jj];
string r = cur.substr(1, 2), g = cur.substr(3, 2), b = cur.substr(5, 2);
sumR += sixteen2ten(r);
sumG += sixteen2ten(g);
sumB += sixteen2ten(b);
//cout<<"i: "<<ii<<" j: "<<jj<<" "<<sixteen2ten(r)<<" "<<sixteen2ten(g)<<" "<<sixteen2ten(b)<<" * ";
}
}
//cout<<endl<<endl;;
myRGB[i][j][0] = sumR / (p * q);
myRGB[i][j][1] = sumG / (p * q);
myRGB[i][j][2] = sumB / (p * q);
}
}
/*
// 输出myRGB
for (int i = 0; i < M; ++i) {
for (int j = 0; j < N; ++j) {
cout<<myRGB[i][j][0]<<" "<<myRGB[i][j][1]<<" "<<myRGB[i][j][2]<<" * ";
}cout<<endl;
}
*/
// 规划输出 (或许可以和上边的合并哈)
string ans = "";
int preR = 0, preG = 0, preB = 0;
string esc, kongge, kuohao, fenhao, zimum, shuzi48, shuzi0, shuzi2, huanhang;
esc = ten2sixteen(27);
kongge = ten2sixteen(' ');
kuohao = ten2sixteen('[');
fenhao = ten2sixteen(';');
zimum = ten2sixteen('m');
shuzi48 = ten2sixteen('4') + ten2sixteen('8');
shuzi0 = ten2sixteen('0');
shuzi2 = ten2sixteen('2');
huanhang = ten2sixteen('\n');
string changBackGround = esc + kuohao + shuzi48 + fenhao + shuzi2 + fenhao; // ESC [ 3 8 ; 2 ;
string resetBackGround = esc + kuohao + shuzi0 + zimum; // ESC [ 0 m
for (int i = 0; i < M; ++i) {
for (int j = 0; j < N; ++j) {
// 先判断当前背景RGB是否与前一个相同
// 相同, 不用改。 只需要添加一个色块
if (myRGB[i][j][0] == preR && myRGB[i][j][1] == preG && myRGB[i][j][2] == preB) {
ans += kongge;
//cout<<"*"<<endl;
}
else { // 不同, 需要改
// 和默认的一致(0,0,0), 使用重置
if (myRGB[i][j][0] == 0 && myRGB[i][j][1] == 0 && myRGB[i][j][2] == 0) {
ans += resetBackGround;
ans += kongge;
}
else {
// ESC [ ; 4 8 ;
ans += changBackGround;
int shang, yu;
// R ;
string curR;
shang = myRGB[i][j][0], yu = 0;
while (shang != 0) { // 这样是倒序的
yu = shang % 10;
shang = shang / 10;
curR = ten2sixteen(yu + '0') + curR; // 这样一下就正序了
}
ans += curR;
//ans += ten2sixteen(myRGB[i][j][0]);
ans += fenhao;
// G ;
string curG;
shang = myRGB[i][j][1], yu = 0;
while (shang != 0) {
yu = shang % 10;
shang = shang / 10;
curG = ten2sixteen(yu + '0') + curG;
}
ans += curG;
ans += fenhao;
// B
string curB;
shang = myRGB[i][j][2], yu = 0;
while (shang != 0) {
yu = shang % 10;
shang = shang / 10;
curB = ten2sixteen(yu + '0') + curB;
}
ans += curB;
//ans += fenhao; /* 不需要!!! B后边不需要分号!!!*/
// 添加 m
ans += zimum;
// 添加色块
ans += kongge;
}
//
preR = myRGB[i][j][0];
preG = myRGB[i][j][1];
preB = myRGB[i][j][2];
}
}
// 该行结束
// 1. 还原成默认背景色, 使用重置 2. 修改preRGB 3. 添加换行符
if (preR != 0 || preG != 0 || preB != 0) {
ans += resetBackGround;
preR = preG = preB = 0;
}
ans += huanhang;
}
cout<<ans;
return 0;
}
100分
20->100: 在十进制转16进制函数中,自己写代码的时候没有考虑当数字为0要输出\x00。改了这个函数以及主函数中最后一个循环中的RGB部分就好了。(注意点3)
#include <iostream>
#include <fstream>
#include <stdlib.h> // sysytem()
#include <map>
using namespace std;
map<char, int> s2t; // 16转10
map<int, char> t2s; // 10转16
// 16进制字符串转10进制数字
int sixteen2ten(string sixteen) {
int num = 0;
for (char c: sixteen) {
num = num * 16 + s2t[c];
}
return num;
}
// 10进制数字转16进制字符串
string ten2sixteen(int ten) {
string sixteen = "";
int shang = 0, yu = 0;
string invSixteen = ""; // 倒序16进制字符串
while (ten != 0) {
yu = ten % 16;
shang = ten / 16;
ten = shang;
invSixteen.push_back(t2s[yu]);
}
// 将逆序的调整为正序
if (invSixteen.size() == 1) {
sixteen = "0";
}
if (invSixteen.size() == 0) { /* 这个不要忘啦 */
sixteen = "00";
//cout<<"HELLO"<<endl;
}
for (int i = invSixteen.size() - 1; i >= 0; --i) {
sixteen.push_back(invSixteen[i]);
}
return "\\x" + sixteen;
}
int main() {
//ifstream cin("in3.txt");
//system("color"); // 使终端能根据输出进行颜色变换
// 初始化
s2t['0'] = 0, s2t['1'] = 1, s2t['2'] = 2, s2t['3'] = 3, s2t['4'] = 4, s2t['5'] = 5, s2t['6'] = 6, s2t['7'] = 7, s2t['8'] = 8, s2t['9'] = 9, s2t['a'] = 10, s2t['b'] = 11, s2t['c'] = 12, s2t['d'] = 13, s2t['e'] = 14, s2t['f'] = 15;
t2s[0] = '0', t2s[1] = '1', t2s[2] = '2', t2s[3] = '3', t2s[4] = '4', t2s[5] = '5', t2s[6] = '6', t2s[7] = '7', t2s[8] = '8', t2s[9] = '9', t2s[10] = 'A', t2s[11] = 'B', t2s[12] = 'C', t2s[13] = 'D', t2s[14] = 'E', t2s[15] = 'F';
int m, n; // 宽、高——列、行
cin>>m>>n;
int p, q; // 每一小块的宽、高——列、行
cin>>p>>q;
// 存储输入 并 填充
string inputStr[n][m]; // 存储输入 , 注意这里是 n行 m列 (有点乱哈)
for (int i = 0; i < n; ++i) { // 高
for (int j = 0; j < m; ++j) { // 宽
string tmp, t;
cin>>tmp;
if (tmp.size() == 2) { // #a -> #aaaaaa
t = tmp;
for (int ii = 0; ii < 5; ++ii) {
t.push_back(tmp[1]);
}
}
else if (tmp.size() == 4) { // #abc -> #aabbcc
t = "#";
for (int ii = 1; ii <= 3; ++ii) {
t.push_back(tmp[ii]);
t.push_back(tmp[ii]);
}
}
else { // #abcdef
t = tmp;
}
//cout<<"i: "<<i<<" j: "<<j<<" t: "<<t<<endl;
inputStr[i][j] = t;
}
}
//cout<<"OK"<<endl;
int M = n / q, N = m / p; // M行N列的色块
int myRGB[M][N][3]; // 记录每一块的RGB平均值
//cout<<M<<" "<<N<<endl;
// 对每个色块中的像素取平均值
for (int i = 0; i < M; ++i) {
for (int j = 0; j < N; ++j) {
// get每个色块的像素
int sumR, sumG, sumB;
sumR = sumG = sumB = 0;
//cout<<i<<" "<<j<<endl;
for (int ii = i * q; ii < i * q + q; ++ii) {
for (int jj = j * p; jj < j * p + p; ++jj) {
string cur = inputStr[ii][jj];
string r = cur.substr(1, 2), g = cur.substr(3, 2), b = cur.substr(5, 2);
sumR += sixteen2ten(r);
sumG += sixteen2ten(g);
sumB += sixteen2ten(b);
//cout<<"i: "<<ii<<" j: "<<jj<<" "<<sixteen2ten(r)<<" "<<sixteen2ten(g)<<" "<<sixteen2ten(b)<<" * ";
}
}
//cout<<endl<<endl;;
myRGB[i][j][0] = sumR / (p * q);
myRGB[i][j][1] = sumG / (p * q);
myRGB[i][j][2] = sumB / (p * q);
}
}
/*
// 输出myRGB
for (int i = 0; i < M; ++i) {
for (int j = 0; j < N; ++j) {
cout<<myRGB[i][j][0]<<" "<<myRGB[i][j][1]<<" "<<myRGB[i][j][2]<<" * ";
}cout<<endl;
}
*/
// 规划输出
string ans = "";
int preR = 0, preG = 0, preB = 0;
string esc, kongge, kuohao, fenhao, zimum, shuzi48, shuzi0, shuzi2, huanhang;
esc = ten2sixteen(27);
kongge = ten2sixteen(' ');
kuohao = ten2sixteen('[');
fenhao = ten2sixteen(';');
zimum = ten2sixteen('m');
shuzi48 = ten2sixteen('4') + ten2sixteen('8');
shuzi0 = ten2sixteen('0');
shuzi2 = ten2sixteen('2');
huanhang = ten2sixteen('\n');
string changBackGround = esc + kuohao + shuzi48 + fenhao + shuzi2 + fenhao; // ESC [ 3 8 ; 2 ;
string resetBackGround = esc + kuohao + shuzi0 + zimum; // ESC [ 0 m
for (int i = 0; i < M; ++i) {
for (int j = 0; j < N; ++j) {
// 先判断当前背景RGB是否与前一个相同
// 相同, 不用改。 只需要添加一个色块
if (myRGB[i][j][0] == preR && myRGB[i][j][1] == preG && myRGB[i][j][2] == preB) {
ans += kongge;
//cout<<"*"<<endl;
}
else { // 不同, 需要改
// 和默认的一致(0,0,0), 使用重置
if (myRGB[i][j][0] == 0 && myRGB[i][j][1] == 0 && myRGB[i][j][2] == 0) {
ans += resetBackGround;
ans += kongge;
}
else {
// ESC [ ; 4 8 ;
ans += changBackGround;
int shang, yu;
// R ;
string curR;
shang = myRGB[i][j][0], yu = 0;
if (shang == 0) {
curR = ten2sixteen('0');
}
else {
while (shang != 0) { // 这样是倒序的
yu = shang % 10;
shang = shang / 10;
curR = ten2sixteen(yu + '0') + curR; // 这样一下就正序了
}
}
ans += curR;
//ans += ten2sixteen(myRGB[i][j][0]);
ans += fenhao;
// G ;
string curG;
shang = myRGB[i][j][1], yu = 0;
if (shang == 0) {
curG = ten2sixteen('0');
}
else {
while (shang != 0) {
yu = shang % 10;
shang = shang / 10;
curG = ten2sixteen(yu + '0') + curG;
}
}
ans += curG;
ans += fenhao;
// B
string curB;
shang = myRGB[i][j][2], yu = 0;
if (shang == 0) {
curB = ten2sixteen('0');
}
else {
while (shang != 0) {
yu = shang % 10;
shang = shang / 10;
curB = ten2sixteen(yu + '0') + curB;
}
}
ans += curB;
//ans += fenhao; /* 不需要!!! B后边不需要分号!!!*/
// 添加 m
ans += zimum;
// 添加色块
ans += kongge;
}
//
preR = myRGB[i][j][0];
preG = myRGB[i][j][1];
preB = myRGB[i][j][2];
}
}
// 该行结束
// 1. 还原成默认背景色, 使用重置 2. 修改preRGB 3. 添加换行符
if (preR != 0 || preG != 0 || preB != 0) {
ans += resetBackGround;
preR = preG = preB = 0;
}
ans += huanhang;
}
cout<<ans;
return 0;
}
代码挺长的,可以修改/删除一些地方(比如规划输出那一段中一长串字符的定义,可以从题目中就知道,就不用再转来转去了),优化一些地方(最后两个大循环应该可以并到一起),删除一些注释掉了的段落,但是懒得弄了。
参考文章
从0分到100分,全靠这篇文章中给出的测试数据。(自己懒了点,也没想到那两个方面)
CCF CSP 20190903 字符画 100分