一杯茶,一根烟,一道模拟做一天。
字符画
思路:
输出注意:
(1)初始时终端的背景色都为默认值(背景黑色);
(2) 如果下一个字符的颜色刚好与默认值完全相同,应当直接使用重置转义序列ESC[0m(即\x1B\x5B\x30\x6D),而非手动更改颜色;
(3)如果某个字符的背景色与其前一个字符相同则直接在前一个字符后输入“空格”(\x20);
(4) 在每行(遇到/x0A几位换行)结尾处,如果终端颜色不是默认值,应该重置终端的颜色状态。
其他注意:
(1)计算每一小块像素的平均值,并将计算出的像素值的ASCII编码转义为16进制编码形式,如像素为255,55,5需要转义为/x32/x35/x35,/x35/x35,/x35。
(2)定义pg,pg,pb保存上一次像素值,每进行第一行或者新一行的运算时需要将pg,pg,pb初始化为默认值0。然后将计算的像素平均值与pg,pg,pb或者默认值0,0,0比较来输出相应的格式。
满分代码:
#include<iostream>
#include<string>
#include<iomanip>
#include<bitset>
#include<cmath>
#include<sstream>
using namespace std;
struct rgb{
int r,g,b;
rgb(int _r=0,int _g=0,int _b=0):r(_r),g(_g),b(_b){}
}block[1100][2000],resblock[1100][2000];
int to_int(string str){//故意写复杂了,其实不需要
int tmp;
int num=0;
int len=str.size();
int carry;
for(int i=0;i<len;i++){
carry=len-1-i;
if(str[i]>='a'&&str[i]<='z')
tmp=str[i]-'a'+10;
else if(str[i]>='A'&&str[i]<='Z')
tmp=str[i]-'A'+10;
else
tmp=str[i]-'0';
num+=pow(16,carry)*tmp;
}
return num;
}
void print(string str){//输出
for(int i=0;i<str.size();i++) //转为ascii码
cout<<"\\x"<<hex<<uppercase<<setw(2)<<int(str[i]);
}
int main(){
int m,n,p,q;
cin>>m>>n>>p>>q;
string color;
//输入
for(int i=0;i<n;i++){
for(int j=0;j<m;j++){
cin >> color;
int r,g,b;
if (color.size() == 2)
color += string(5, color[1]);
else if (color.size() == 4)
color = string(1, color[0]) + string(2, color[1]) + string(2, color[2]) + string(2, color[3]);
r=to_int(color.substr(1,2));
g=to_int(color.substr(3,2));
b=to_int(color.substr(5,2));
block[i][j]=rgb(r,g,b);
//cout<<r<<" "<<g<<" "<<b<<endl;
}
}
//处理小块,即求平均值
for(int i=0;i<n/q;i++){
for(int j=0;j<m/p;j++){
int r=0,g=0,b=0;
for(int ki=q*i;ki<q*(i+1);ki++){
for(int kj=p*j;kj<p*(j+1);kj++){
r+=block[ki][kj].r;
g+=block[ki][kj].g;
b+=block[ki][kj].b;
}
}
//cout<<r/(p*q)<<" "<<g/(p*q)<<" "<<b/(p*q)<<endl;
resblock[i][j]=rgb(r/(p*q),g/(p*q),b/(p*q));
}
}
//输出每一个小块
int dr=0,dg=0,db=0;
int pr=0,pg=0,pb=0;
for(int i=0;i<n/q;i++){
for(int j=0;j<m/p;j++){
int r=resblock[i][j].r,g=resblock[i][j].g,b=resblock[i][j].b;
if(r==pr&&g==pg&&b==pb){}//如果和前一个小块一样
else if(r==dr&&g==dg&&b==db){//如果和默认一样
pr=dr,pg=dg,pb=db;//更新
cout << "\\x1B\\x5B" << "\\x30\\x6D";
}
else{//如果都不一样
pr=r,pg=g,pb=b;//更新
string rr,gg,bb;
stringstream ss;//int->string,懒得写个函数了,可能慢点
ss<<r,ss>>rr,ss.clear();
ss<<g,ss>>gg,ss.clear();
ss<<b,ss>>bb,ss.clear();
print("\x1b[48;2;"+rr+";"+gg+";"+bb+"m");//输出
}
cout<<"\\x20";//每个小块结束,都输出一个空格
}
if(pr!=dr||pg!=dg||pb!=db){//换行判断结尾是否为默认值
cout << "\\x1B\\x5B" << "\\x30\\x6D";
pr=dr,pg=dg,pb=db;//更新为默认值
}
cout<<"\\x0A";//输出一个换行符
}
return 0;
}
测试样例:
输入1
1 1
1 1
#010203
输出1
\x1B\x5B\x34\x38\x3B\x32\x3B\x31\x3B\x32\x3B\x33\x6D\x20\x1B\x5B\x30\x6D\x0A
输入2
2 2
1 2
#111111
#0
#000000
#111
输出2
\x1B\x5B\x34\x38\x3B\x32\x3B\x38\x3B\x38\x3B\x38\x6D\x20\x20\x1B\x5B\x30\x6D\x0A
输入3
1 1
1 1
#0
输出3
\x20\x0A
输入4
2 2
2 1
#111111
#0
#000000
#111
输出4
\x1B\x5B\x34\x38\x3B\x32\x3B\x38\x3B\x38\x3B\x38\x6D\x20\x1B\x5B\x30\x6D\x0A\x1B\x5B\x34\x38\x3B\x32\x3B\x38\x3B\x38\x3B\x38\x6D\x20\x1B\x5B\x30\x6D\x0A
输入5
2 2
2 1
#111111
#0
#000000
#000
输出5
\x1B\x5B\x34\x38\x3B\x32\x3B\x38\x3B\x38\x3B\x38\x6D\x20\x1B\x5B\x30\x6D\x0A\x20\x0A
输入6
3 2
1 2
#0
#0
#010101
#010102
#0
#0
输出6
\x1B\x5B\x34\x38\x3B\x32\x3B\x30\x3B\x30\x3B\x31\x6D\x20\x1B\x5B\x30\x6D\x20\x20\x0A
输入7
1 2
1 2
#123456
#abcdef
输出7
\x1B\x5B\x34\x38\x3B\x32\x3B\x39\x34\x3B\x31\x32\x38\x3B\x31\x36\x32\x6D\x20\x1B\x5B\x30\x6D\x0A
输入8
2 1
2 1
#654321
#fedcba
输出8
\x1B\x5B\x34\x38\x3B\x32\x3B\x31\x37\x37\x3B\x31\x34\x33\x3B\x31\x30\x39\x6D\x20\x1B\x5B\x30\x6D\x0A