第二十二天 2021-4-5 备战CSP
刷题模块:CSP 201909-1-2-3
编程格式向任神看齐 :CSP 201909-3 字符画
一、201909-1
第一题,无难度
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll N,M;
ll K,t,P;
ll op;
void init(){
K=t=P=0;
}
int main(){
freopen("in.txt","r",stdin);
init();
scanf("%lld%lld",&N,&M);
for(int i=0;i<N;i++){
ll tmpP=0;
scanf("%lld",&op);
K+=op;
for(int j=1;j<M+1;j++){
scanf("%lld",&op);
K+=op; //the amount of the apple,currently add all
tmpP+=op;
}
if(tmpP<P){
P=tmpP;
t=i+1;
}
}
printf("%lld %lld %lld",K,t,-P);
return 0;
}
二、201909-2
不是很难,不需要存储状态再判断,只需要输入时判断并且存储四个状态用来环的特判即可。
注意第一次只拿了90分,忘记了三棵树的特判的特判,明明看到了前两个测试点n为3。(QAQ)
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll n,m;
ll fall; //for 3 three count
bool isFall,isFallSpec[4]; //judge this tree is falling apple?
ll T,D,E;
ll appleNum,num;
int idx;
void init(){
idx=0;
fall=0;
T=D=E=0;
}
int main(){
freopen("in.txt","r",stdin);
init();
scanf("%lld",&n);
for(int i=0;i<n;i++){
scanf("%lld%lld",&m,&appleNum);
isFall=false;
for(int j=1;j<m;j++){
scanf("%lld",&num);
if(num>0 && num!=appleNum){
appleNum=num;
isFall=true;
}
else if(num<=0){
appleNum+=num;
}
}
if(i==0 || i==1 || i==n-1 || i==n-2) isFallSpec[idx++]=isFall;
if(isFall) fall++;
else fall=0;
if(isFall) D++;
if(fall>=3) E++;
T+=appleNum;
}
if(idx==4){
if(isFallSpec[3] && isFallSpec[0] && isFallSpec[1]) E++;
if(isFallSpec[2] && isFallSpec[3] && isFallSpec[0]) E++;
}
else{
if(isFallSpec[2] && isFallSpec[0] && isFallSpec[1]) E++;
if(isFallSpec[1] && isFallSpec[2] && isFallSpec[0]) E++;
}
printf("%lld %lld %lld",T,D,E);
return 0;
}
二、201909-3
字符串操作仍然不太熟练,直接参考任神的解答CSP 201909-3 字符画
这代码真的太妙了,看的赏心悦目。
1. 重要模块:字符串转换为"\xAB"形式输出
1. 使用\\转义输出反斜杠;
2. 使用%02X来输出字符对应的大写16进制数,其中的02保证两位数,不足补0;
3. printStr将字符串拆分,一个一个转换输出;
4. sprintf函数使得构造字符串变得简单,只需要预设ch即可。
char ch[]="\x1b[48;2;%d;%d;%dm";
char strs[1000];
sprintf(strs,ch,255,255,255);
inline void printChar(int ch) {
printf("\\x%02X", ch);
}
inline void printStr(const char* s) {
while (*s) {
printChar(*s);
s++;
}
}
2. 重要模块:输入构造
1.吞掉输入字符串中的子字符串,使用scanf("#");
比输入后再删除更高效
scanf("\n#");//注意一定要把换行也吞掉,否则会匹配失败
scanf("%s", strs);
2. 如何转换16进制字母到10进制数:c-'a'+10
3. 16进制乘法:0xaa=0xa*0x11
使用scanf("\n#");吞掉字符时,一定要将换行也考虑在内。使用时请制作测试案例来测试是否成功输入
int transNum1(char c) {
if ('0' <= c && c <= '9')return c - '0';
else if ('a' <= c && c <= 'f')return c - 'a' + 10;
else if ('A' <= c && c <= 'F')return c - 'A' + 10;
else return -1;
}
arr[i][j][0] = low4 * 0x11;
3. 重要模块:数值转换
代码十分优美,注重过程功能函数化,逻辑清晰
inline void calculateAvgSub(int blockX, int blockY) {
unsigned long long x = 0, y = 0, z = 0;
for (int i = blockX * q; i < (blockX + 1) * q; i++) {
for (int j = blockY * p; j < (blockY + 1) * p; j++) {
x += arr[i][j][0];
y += arr[i][j][1];
z += arr[i][j][2];
}
}
arrAvg[blockX][blockY][0] = x / q / p;
arrAvg[blockX][blockY][1] = y / q / p;
arrAvg[blockX][blockY][2] = z / q / p;
}
void calculateAvg() {
for (int i = 0; i < v; i++) {
for (int j = 0; j < u; j++) {
calculateAvgSub(i, j);
}
}
}
3. 注意点:坐标转换
题目中叙述和输入顺序均为先宽m后高n,而实际上高为行数,宽为列数。
扫描输入时,转换时,输出时需要逐行进行,所以一定要先高后宽。
for(n){
for(m){}
}
4. 注意点:unsigned char
char类型占用一字节,取值范围-128~127
unsigned char占用一字节,取值范围0~255
使用unsigned char十分细节,刚好储存颜色数值,并且不浪费存储空间
三、C++:sprintf()
#include<iostream>
#include<cstdio>
using namespace std;
int main()
{
char str[80];
sprintf(str, "Pi µÄÖµ = %f", 3.14);puts(str);
sprintf(str,"%-6x",31);puts(str);
sprintf(str,"%6x",31);puts(str);
sprintf(str,"%06X",31);puts(str);
return(0);
}
三、C++:字符串函数
具体示例请参考:C++字符串函数详解
#include<cstring>
函数 | 功能 |
---|---|
strlen(str) | 返回字符串的长度,不包括终止符 |
strcat(str1,str2) | 连接两个字符串,请确保str1足够大 |
strcpy(str1,str2) | 将str2内容复制到str1,str1若有内容将被覆盖,请确保str1足够大 |
strcmp(str1,str2) | 返回值为0则相等,大于0则str1字符较大,反之同理。 |
C++ string类可以直接使用==比较,==已被重载
C++ char[]数组不可使用==比较,将比较内存地址。请使用strcmp