部分题解|蓝桥杯第十五届校模拟赛第一期
前言
本次蓝桥杯校内模拟赛第一期的题目,C/C++组共13道题,其中6道填空(前五道+中间还有一道,不知道为什么这么排),7道程序设计大题。
涉及算法知识点:模拟、暴力、BFS、DFS、贪心,填空题多涉及模拟以及逻辑思维题,较为容易。
用了大约3小时,做出来5道填空题,5道大题。如果能把BFS和DFS再复习一下,应该能拿下6道选择,6道大题。
校模拟赛相比省赛难度低到不知道哪里去了,毕竟模拟赛出的简单了才好拉大家进来收割省赛报名300块(乐)。
填空题
第一题 难度⭐
题干
请找到一个大于 2022 的最小数,这个数转换成十六进制之后,所有的数位(不含前导 0)都为字母(A 到 F)。
请将这个数的十进制形式作为答案提交。
题目分析
十六进制的数,每一位上都是0 1 2 … 9、A B C …F 排列的(共16个数)。我们先用win自带计算器将 2022 转为十六进制,得到 7E6 。
也就是说,想要让三个位置上都为字母,且都是最小的,即让每位都为A即可。本题无需编程,纯逻辑题。
题解
在十六进制模式下,将AAA输入win计算器,得到十进制数 2730,为最终答案。
第二题 难度⭐
题干
在 Excel 中,列的名称使用英文字母的组合。前 26 列用一个字母,依次为 A 到 Z,接下来 26*26 列使用两个字母的组合,依次为 AA 到 ZZ。
请问第 2022 列的名称是什么?
题目分析
这道题有两种方法解,第一种需要打开电脑上Excel直接实际操作去解(半分钟搞定),第二种用编程思路。
第一种方法简单一说,就是在Excel点选第A列然后按住向右拖动,直到上面的数为2022为止,这里我拖到27,对应列数为AA 。
第二种方法,编程。先摸清楚列数的规律,举个例子,AB代表28,将 28 % 26 =2 ,这里的2代表最低位的B列,再将(28-2)/26 =1 ,1%26=1,这里的1代表下一顺位的A列。将两次结果组成一个字符串,也就是AB。
懂了规律后就很容易编程了。
题解
#include <bits\stdc++.h>
using namespace std;
int main(){
int a = 2022,ans;
char arr[10];
int i=0;
while(a){
//取得的余数,本来是1代表A,26代表了Z,但为了转为字符串,我们加上字符A,需要先减 1,也就是1-1+'A'='A';26-1+'A'='Z'
arr[i++]=a%26 -1 + 'A';
a = (a-(a%26))/26;
}
for(int i=strlen(arr);i>=0;i--) // 从高位开始取字母,这样打印出来的正好顺次。
cout<<arr[i];
return 0;
}
最终答案为 BYT
第三题 难度 ⭐
题干
对于一个日期,我们可以计算出年份的各个数位上的数字之和,也可以分别计算月和日的各位数字之和。请问从 1900 年 1 月 1 日至 9999 年 12 月 31 日,总共有多少天,年份的数位数字之和等于月的数位数字之和加日的数位数字之和。
例如,2022年11月13日满足要求,因为 2+0+2+2=(1+1)+(1+3) 。
请提交满足条件的日期的总数量
题目分析
主要考察的是闰年的判断和取数位的方法,整体难度很低。
题解
#include <bits\stdc++.h>
using namespace std;
int pd(int y){ //判断是闰年还是平年
if((y%4==0&&y%100!=0) || y%400==0)
return 1;
return 0;
}
int fun(int x){ //分解每个数字数位并对其求和
int sum=0;
while(x)
{
sum += x%10;
x/=10;
}
return sum;
}
int main(){
int cnt=0;
int months1[13] = {0,31,28,31,30,31,30,31,31,30,31,30,31};
int months2[13] = {0,31,29,31,30,31,30,31,31,30,31,30,31};
for(int i=1900;i<=9999;i++){
if(pd(i)){ //闰年
for(int j=1;j<=12;j++){
for(int k=1;k<=months2[j];k++)
{
if(fun(i)==(fun(j)+fun(k)))
cnt++;
}
}
}
else{
{ //非闰年
for(int j=1;j<=12;j++){
for(int k=1;k<=months1[j];k++)
{
if(fun(i)==(fun(j)+fun(k)))
cnt++;
}
}
}
}
}
cout<<cnt;
return 0;
}
最终答案 70910
第四题 难度⭐
题干
小蓝有 30 个数,分别为:99, 22, 51, 63, 72, 61, 20, 88, 40, 21, 63, 30, 11, 18, 99, 12, 93, 16, 7, 53, 64, 9, 28, 84, 34, 96, 52, 82, 51, 77 。
小蓝可以在这些数中取出两个序号不同的数,共有 30*29/2=435 种取法。
请问这 435 种取法中,有多少种取法取出的两个数的乘积大于等于 2022 。
题目分析
从第1个取到第29个数,让第i个数其与后面29-i+1个数分别做乘积,判断是否大于等于2022即可。
题解
#include <bits\stdc++.h>
using namespace std;
int main(){
int arr[]= {99, 22, 51, 63, 72, 61, 20, 88, 40, 21, 63, 30, 11, 18, 99, 12, 93, 16, 7, 53, 64, 9, 28, 84, 34, 96, 52, 82, 51, 77};
int cnt=0;
for(int i=0;i<29;i++)
{
for(int j=i+1;j<30;j++)
{
if(arr[i]*arr[j]>=2022) cnt++;
}
}
cout<<cnt;
return 0;
}
答案 189
第五题 难度 ⭐⭐⭐
题干
小蓝有一个 30 行 60 列的数字矩阵,矩阵中的每个数都是 0 或 1 。
110010000011111110101001001001101010111011011011101001111110
010000000001010001101100000010010110001111100010101100011110
001011101000100011111111111010000010010101010111001000010100
101100001101011101101011011001000110111111010000000110110000
010101100100010000111000100111100110001110111101010011001011
010011011010011110111101111001001001010111110001101000100011
101001011000110100001101011000000110110110100100110111101011
101111000000101000111001100010110000100110001001000101011001
001110111010001011110000001111100001010101001110011010101110
001010101000110001011111001010111111100110000011011111101010
011111100011001110100101001011110011000101011000100111001011
011010001101011110011011111010111110010100101000110111010110
001110000111100100101110001011101010001100010111110111011011
111100001000001100010110101100111001001111100100110000001101
001110010000000111011110000011000010101000111000000110101101
100100011101011111001101001010011111110010111101000010000111
110010100110101100001101111101010011000110101100000110001010
110101101100001110000100010001001010100010110100100001000011
100100000100001101010101001101000101101000000101111110001010
101101011010101000111110110000110100000010011111111100110010
101111000100000100011000010001011111001010010001010110001010
001010001110101010000100010011101001010101101101010111100101
001111110000101100010111111100000100101010000001011101100001
101011110010000010010110000100001010011111100011011000110010
011110010100011101100101111101000001011100001011010001110011
000101000101000010010010110111000010101111001101100110011100
100011100110011111000110011001111100001110110111001001000111
111011000110001000110111011001011110010010010110101000011111
011110011110110110011011001011010000100100101010110000010011
010011110011100101010101111010001001001111101111101110011101
如果从一个标为 1 的位置可以通过上下左右走到另一个标为 1 的位置,则称两个位置连通。与某一个标为 1 的位置连通的所有位置(包括自己)组成一个连通分块。
请问矩阵中最大的连通分块有多大?
题目分析
很明显的BFS
题目。先遍历矩阵,找到数值为1的且未被BFS遍历过的点,将其压入队列,执行BFS操作。在BFS操作中注意计数,BFS函数返回当前连通分块的值,在主函数中把该值与当前最大值比较,以判断是否更新最大值。
题解
#include <bits/stdc++.h>
using namespace std;
int Map[31][61];
int done[40][70]={0};
int dy[4]={0,1,0,-1};
int dx[4]={1,0,-1,0};
typedef pair<int,int> PII;
queue<PII> q;
PII temppair;
int check(int x,int y)
{
if(x<0 || x>=30 || y<0 || y>=60) //出界判断
return 0;
if(Map[x][y]==0)
return 0;
if(done[x][y]==1)
return 0;
return 1;
}
int bfs(){
int cnt = 0;
while(!q.empty()){
temppair = q.front();
q.pop();
for(int i=0;i<4;i++)
{
int nowx = temppair.first+dx[i];
int nowy = temppair.second+dy[i];
if(check(nowx,nowy))
{
q.push({nowx, nowy});
done[nowx][nowy]=1;
cnt++;
}
}
}
return cnt;
}
int main(){
for(int i=0;i<30;i++)
for(int j=0;j<60;j++)
{
scanf("%1d", &Map[i][j]); //小技巧,scanf可以固定输入位数
}
int MAX = -1;
for(int i=0;i<30;i++)
{
for(int j=0;j<60;j++)
{
if(Map[i][j]==1&&done[i][j]==0)
{
q.push({i,j});
MAX = max(MAX,bfs());
}
}
}
cout<<MAX;
return 0;
}
答案 148
第十一题 难度⭐
题干
一个数的数位和是指这个数各个数位上的数字之和。例如 2023 的数位和是 2+0+2+3=7 。
对于以下这些数(8行,每行8个,共64个),请问数位和最小的数是多少?(如果有多个,请回答出现最早的那个)
454771 329157 801601 580793 755604 931703 529875 361797
604358 529564 574776 821517 195563 688516 223321 607845
284772 603562 543328 707484 533688 380468 233733 257995
896582 670074 912386 702393 722092 834842 126346 606526
376981 910643 413754 945725 817853 651778 350775 676550
316935 487808 939526 900568 423326 298936 927671 539773
136326 717022 886675 466684 436470 558644 267231 902422
743580 857864 529622 320921 595409 486860 951114 558787
题目分析
这题是填空,还放在第十一题,难度根本就是非线性的啊,太水了吧!!
将所有数字扔进一个数组arr里,然后创一个函数,用途是数位依次拆分,加和,放进记录数位和的数组。然后挨个取数位和数组,与现有的最小数位和min相比较,比它小就记录数组下标imin。最后输出数组arr[imin]
题解
#include <bits\stdc++.h>
using namespace std;
int fun(int a) //求数位和
{
int sum=0;
while(a)
{
sum+=a%10;
a/=10;
}
return sum;
}
int main(){
int arr1[100],arr2[70];
for(int i=0;i<64;i++)
cin>>arr1[i];
int k=0;
for(int i=0;i<64;i++)
arr2[k++]=fun(arr1[i]);
int min=999999,imin=0;
for(int j=0;j<k;j++)
{
if(arr2[j]<min)
{
imin=j;
min=arr2[j];
}
}
cout<<arr1[imin];
return 0;
}
答案 223321