第十四届蓝桥杯模拟赛(第三期)—保姆级解释(C语言版)

1.找最小数

问题描述:

请找到一个大于 2022 的最小数,这个数转换成十六进制之后,所有的数位(不含前导 0)都为字母(A 到 F)。

请将这个数的十进制形式作为答案提交。

//1.最小数
int main()
{
    int i = 2023;
    
    for ( i = 2023; i; i++)//for循环中不写第二个条件即没有限制条件,此循环可以一直进行
    {
      int sum = i;//定义一个sum来进行判断,如果最小数则直接返回i(因为sum已经被改变)
       char ch = 0;//定义一个字符,讲每个除下来的数进行字符转换去比较
        while(sum!=0)
        {
            ch = sum % 16+'0';//因为除下来的数为整形所以要加‘0’进行字符类型转换
            if (ch<='9')//因为16进制最小的字母为a,整形数字为10,所以要判断每次除下来数的是否<=9。
            {
                break;//若<=9则直接终止此次循环进行下一次的for循环。
            }
            else
            {
                sum /= 16;//因为为16进制判断所以每次要除16。
            }
        }
        //当每次除下来的数(每位数)都大于9时说明这个数符合题目要求,且此时sum已经为0;
        if (sum==0)
        {
            break;//这里我们再来判断sum是否已经为0,若为0则直接跳出for循环。
        }
    }
    printf("%d\n", i);//因为我们把i赋值给了sum再来判断,i保留了真正的答案所以打印i;
    return 0;
}
答案2730

第二题,填空题

问题描述

  在 Excel 中,列的名称使用英文字母的组合。前 26 列用一个字母,依次为 A 到 Z,接下来 26*26 列使用两个字母的组合,依次为 AA 到 ZZ。

  请问第 2022 列的名称是什么?

答案提交

  这是一道结果填空的题,你只需要算出结果后提交即可。本题的结果为一个由大写字母组成的字符串,在提交答案时只填写这个字符串,填写多余的内容将无法得分。

//2.求列名
//这道题可以看作把十进制2022转换为26进制来代表(按题中意思,26进制1-26用A-Z来表示)
int main()
{
    //我们来定义一个数组来保存每次2022%26的余数最后再来转换成26进制符号(题中A-Z)来表示;
    int arr[4] = { 0 };//这里我们把数组大小定义小点,因为26进制转换成10进制的数很大,4个空间足矣。
    int sum = 2022;
    int i = 0;
    while (sum)
    {
        arr[i++] = sum % 26;//用来保存余数,存放完后我们i++方便下一个数组空间存放新的余数。
        sum /= 26;
    }
    for(int j=i-1;j>=0;j--)//依据十进制与二进制的转换是从后向前排序,所以我们先把i-1赋值给j先改变最后一个余数。不理解的可以举个十进制转换成二进制,依次除2后倒着排序。
    {        //我们把余数赋值后立马i++,意为我们先找到下一个数组空间再赋值,但是最后的时候sum/26=0了无法再进入while循环,但是我们i已经在上次循环多加了一次,所以要i-1
        printf("%c",'A' + arr[j] - 1);//为什么arr[j]-1,举例子我们第一个余数为20转换成26进制符号为 T 但是A加20为U多加了一次所以要减一。
                                      //为什么不能直接‘0‘+arr[j]-1,因为我们转换为字母所以要根据ascii码来大写字母从A(十进制:97)开始不能直接把20转换为对应的ASCII码
                                      //所以要先用A加再减1.
    }
return 0;
}
答案:BYT

3.求日期数

问题描述:

对于一个日期,我们可以计算出年份的各个数位上的数字之和,也可以分别计算月和日的各位数字之和。请问从 1900 年 1 月 1 日至 9999 年 12 月 31 日,总共有多少天,年份的数位数字之和等于月的数位数字之和加日的数位数字之和。例如,2022年11月13日满足要求,因为 2+0+2+2=(1+1)+(1+3) 。

请提交满足条件的日期的总数量。

//3.求日期数
//求各为数的和函数
int just(int x)//判断是否为闰年的函数,如果是闰年则返回1
{
    if (x % 400 == 0 || (x % 4 == 0&&x%100!=0))
    {
        return 1;
    }
    else
    {
        return 0;
    }
}
int add(int y)//我们定义一个函数用来求年 月 日,各位上的数字相加之和。
{
    int sum = 0;
    while (y)
    {
        sum += y % 10;
        y /= 10;
    }
    return sum;
}
int main()
{
    int month[13] = { 0,31,28,31,30,31,30,31,31,30,31,30,31};//定义一个数组,让每个月月份对应其坐标,数组内容为对应月的天数。
    int i = 0;
    int count = 0;//用来统计符号条件的日期次数
    for (i = 1900; i <10000; i++)
    {
        //把年份传参给函数just如果是闰年则二月为29天否则为28天
        if (just(i))
        {
            month[2] = 29;
        }
        else
        {
            month[2] = 28;
        }
        int yearAdd = add(i);//我们i也就是年份传参到函数add用来计算年各位相加之和
        int j = 0;
        for (j = 1; j < 13; j++)//月循环
        {
            int k = 0;
            for (k = 1; k <= month[j]; k++)//每月对应有几天(month[j])来循环
            {
                int m_dAdd = add(j) + add(k);
                if (yearAdd == m_dAdd)//如果年各位数相加和等于日与月各位数相加和则count++
                {
                    count++;
                }
            }
        }
    }
    
    printf("%d\n", count);//最后输出符合条件日期的总个数。
    return 0;
}
答案:70910

4.取数

问题描述:

小蓝有 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 。

//4.取数
int main()
{
    int count = 0;
    int arr[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 };
    for (int i = 0; i < sizeof(arr)/sizeof(arr[0]); i++)//先循环第一次,每个数都循环一变
    {
        for ( int j = i+1;  j <sizeof(arr) / sizeof(arr[0]);  j++)//第二数是从都一个属往后开始计数。
        {
            
             if ((arr[i]*arr[j])>=2022)
            {
                count++;
            }
            
        }
    }
    printf("%d\n", count);
    return 0;
}
答案189

5.最大连通分块

(本题为dfs算法目前博主还没有涉及)可参考:https://blog.csdn.net/m0_74183164/article/details/129453651

问题描述:

小蓝有一个 30 行 60 列的数字矩阵,矩阵中的每个数都是 0 或 1 。

如果从一个标为 1 的位置可以通过上下左右走到另一个标为 1 的位置,则称两个位置连通。与某一个标为 1 的位置连通的所有位置(包括自己)组成一个连通分块。

  请问矩阵中最大的连通分块有多大?


6.n天后周几

输入格式

  输入第一行包含一个整数 w,表示给定的天是一周中的哪天,w 为 1 到 6 分别表示周一到周六,w 为 7 表示周日。第二行包含一个整数 n。

输出格式

  输出一行包含一个整数,表示 n 天后是一周中的哪天,1 到 6 分别表示周一到周六,7 表示周日。。

评测用例规模与约定

  对于所有评测用例,1 <= n <= 1000000。

//6.顺还队列的思想
int main()
{
    int day = 0;
    printf("请输入周几:>\n");
    scanf_s("%d", &day);
    int n = 0;
    printf("请输入往后的天数:>\n");
    scanf_s("%d", &n);
    int ret = (day + n) % 7;
    if (ret==0)
    {
        ret += 1;
    }
    printf("%d\n", ret);
    return 0;
}
样例输入
6
10
样例输出
2

7.信号塔信号覆盖点数

问题描述

  小蓝负责一块区域的信号塔安装,整块区域是一个长方形区域,建立坐标轴后,西南角坐标为 (0, 0), 东南角坐标为 (W, 0), 西北角坐标为 (0, H), 东北角坐标为 (W, H)。其中 W, H 都是整数。

  他在 n 个位置设置了信号塔,每个信号塔可以覆盖以自己为圆心,半径为 R 的圆形(包括边缘)。

  为了对信号覆盖的情况进行检查,小蓝打算在区域内的所有横纵坐标为整数的点进行测试,检查信号状态。其中横坐标范围为 0 到 W,纵坐标范围为 0 到 H,总共测试 (W+1) * (H+1) 个点。

  给定信号塔的位置,请问这 (W+1)*(H+1) 个点中有多少个点被信号覆盖。

输入格式

  输入第一行包含四个整数 W, H, n, R,相邻整数之间使用一个空格分隔。

  接下来 n 行,每行包含两个整数 x, y,表示一个信号塔的坐标。信号塔可能重合,表示两个信号发射器装在了同一个位置。

输出格式

输出一行包含一个整数,表示答案。

评测用例规模与约定 对于所有评测用例,1 <= n <= 100,每个单词的长度不超过 100。

//7.信号塔信号覆盖点数
int main()
{
    int W = 0;//x轴
    int H = 0;//y轴
    int n = 0;//需要放置信号的次数
    int R = 0;//半径
    int arr[101][101];//定义最大的坐标系xy坐标
    int i = 0;
    int j = 0;
    int count = 0;//用来统计被覆盖点的个数
    scanf_s("%d %d %d %d", &W, &H, &n, &R);
    int x = 0;
    int y = 0;//定义x,y即我们要放置信号的坐标
    while (n--)//防止n个每一次放置先进行排查所以为n--
    {
        scanf_s("%d %d", &x, &y);//输入放置信号的坐标
        arr[x][y] = 1;
        for (i = 0; i <=W; i++)//x轴每次循环
        {
            for (j = 0;  j <=H;  j++)//y轴每次循环
            {
                if ((i - x) * (i - x) + (j - y) * (j - y) <= pow(R, 2))//这里我们运用了高中知识,即每次测试的坐标与xy比看两点之间的距离是否小于等于R如果<=说明被覆盖
                {                                                      //两点之间距离:(x1-x2)^2+(y1-y2)^2                {
                    arr[i][j] = 1;//我们把每次被覆盖(与xy距离小于等于半径)的点赋值为1.
                }
            }
        }
    }
    for ( i = 0; i <= W; i++)
    {
        for ( j = 0; j <= H; j++)
        {
            if (arr[i][j] == 1)//这样我们用count统计,输出所有点,若被赋值为1则count++
                count++;
        }
    }
    printf("%d\n", count);
    return 0;
}
样例输入
10 10 2 5
0 0
7 0
样例输出
57

8.清理水草

问题描述

  小蓝有一个 n * m 大小的矩形水域,小蓝将这个水域划分为 n 行 m 列,行数从 1 到 n 标号,列数从 1 到 m 标号。每行和每列的宽度都是单位 1 。

  现在,这个水域长满了水草,小蓝要清理水草。

  每次,小蓝可以清理一块矩形的区域,从第 r1 行(含)到第 r2 行(含)的第 c1 列(含)到 c2 列(含)。

  经过一段时间清理后,请问还有多少地方没有被清理过。

输入格式

  输入第一行包含两个整数 n, m,用一个空格分隔。

  第二行包含一个整数 t ,表示清理的次数。

  接下来 t 行,每行四个整数 r1, c1, r2, c2,相邻整数之间用一个空格分隔,表示一次清理。请注意输入的顺序。

输出格式

  输出一行包含一个整数,表示没有被清理过的面积。

评测用例规模与约定

  对于所有评测用例,1 <= r1 <= r2 <= n <= 100, 1 <= c1 <= c2 <= m <= 100, 0 <= t <= 100。

//8.清理水草
int main()
{
    int arr[100][100] = {100};//我们定义一个二维数组假设为n m的最大值
    int n = 0;
    int m = 0;
    scanf_s("%d %d", &n, &m);//先输入n m的值也就是矩形水域的长和宽
    int t = 0;
    scanf_s("%d",&t);//输入要清理的次数
    int x1 = 0, y1 = 0;
    int x2 = 0, y2 = 0;
    int i = 0;
    int j = 0;
    int count = 0;
    while (t--)
    {
        scanf_s("%d %d %d %d", &x1, &y1, &x2, &y2);//输入每次清理从第x1行的第y1列到x2行的y2列
        for (i = x1-1; i <= x2-1; i++)//这里for循环中的x y都要-1,因为在数组中起始坐标为0,而我们生活中是以1开头的
        {                             //如我们想清理(1,1)也就是第一行第一列,而在数组中的表示为(0,0).
            for ( j = y1-1; j <=y2-1; j++)
            {
                    arr[i][j] = 1;//我们把已经清理的面积赋值为1.
            }
        }
        
    }
    //把所有的数组(水域面积)都遍历一边,如果不等于1则是我们没有清理的水域,用count统计。
    for (i = 0; i < n; i++)
    {
        for (j = 0; j < m; j++)
        {
            if (arr[i][j] != 1)
            {
                count++;//我们用count来统计没有清理过的水域,每日记录一个count++
            }
        }
    }
    printf("%d ", count);//最后我们输入count的值也就是没有清理的面积
    return 0;
}
样例输入
2 3
2
1 1 1 3
1 2 2 2
样例输出
2
样例输入
30 20
2
5 5 10 15
6 7 15 9
样例输出
519

9.滑行距离

(此题也为dfs法可参考第五题链接)

问题描述

  小蓝准备在一个空旷的场地里面滑行,这个场地的高度不一,小蓝用一个 n 行 m 列的矩阵来表示场地,矩阵中的数值表示场地的高度。

  如果小蓝在某个位置,而他上、下、左、右中有一个位置的高度(严格)低于当前的高度,小蓝就可以滑过去,滑动距离为 1 。

  如果小蓝在某个位置,而他上、下、左、右中所有位置的高度都大于等于当前的高度,小蓝的滑行就结束了。

  小蓝不能滑出矩阵所表示的场地。

  小蓝可以任意选择一个位置开始滑行,请问小蓝最多能滑行多远距离。

输入格式

  输入第一行包含两个整数 n, m,用一个空格分隔。

  接下来 n 行,每行包含 m 个整数,相邻整数之间用一个空格分隔,依次表示每个位置的高度。

输出格式

  输出一行包含一个整数,表示答案。

评测用例规模与约定

对于 30% 评测用例,1 <= n <= 20,1 <= m <= 20,0 <= 高度 <= 100。

对于所有评测用例,1 <= n <= 100,1 <= m <= 100,0 <= 高度 <= 10000。


10.求最小值

问题描述

  小蓝有一个序列 a[1], a[2], …, a[n]。

  给定一个正整数 k,请问对于每一个 1 到 n 之间的序号 i,a[i-k], a[i-k+1], …, a[i+k] 这 2k+1 个数中的最小值是多少?当某个下标超过 1 到 n 的范围时,数不存在,求最小值时只取存在的那些值。

输入格式

  输入的第一行包含一整数 n。

  第二行包含 n 个整数,分别表示 a[1], a[2], …, a[n]。

  第三行包含一个整数 k 。

输出格式

  输出一行,包含 n 个整数,分别表示对于每个序号求得的最小值。

评测用例规模与约定

  对于 30% 的评测用例,1 <= n <= 1000,1 <= a[i] <= 1000。

  对于 50% 的评测用例,1 <= n <= 10000,1 <= a[i] <= 10000。

  对于所有评测用例,1 <= n <= 1000000,1 <= a[i] <=1000000。

//10.求最小值
#define MAX_SIZE 1000001//我们先宏定义一个最大数来代替我们数组的空间。
long long arr[MAX_SIZE] = { 0 };//数组空间过大时要开在上面,防止爆 。
//因题目要求数字最大值过大所以我们用long long类型
int main()
{
    long long n=0;
    long long min = 0;
    scanf_s("%lld", &n);//先输入数子的个数。
    for (int i=1; i<=n; i++)//进行循环,挨个输入每个数字共n个。
    {
        scanf_s("%lld",&arr[i]);
    }
    long long k = 0;
    scanf_s("%lld",&k);//输入整数k。
    for (int i=1; i<=n; i++)
    {
       min = 1000010;//我们定义一个min,但要复制一个较大数,这样比较的时候比它小的再赋值给min
        for (int j=0; j<=2*k; j++)
        {
            if ((i-k+j)>n||(i-k+j)<1)//如题目要求,下表不在1-n之间的则直接跳过。
            {
                continue; //这里我们用continue意味这次循环不符合进行下一次。因为如果下表小于1,但后面的循环下标符合,所以不能用break。
            }
            min = min > arr[i - k + j] ? arr[i - k + j] : min;//这里我们用判断语句将每个序号所对应的数与min比较,比它小的我们则赋值给min,然后再打印出来。
        }
        printf("%lld ", min);//最后我们打印每次循环的最小值
    }
    return 0;
}
样例输入
5
5 2 7 4 3
1
样例输出
2 2 2 3 3

第三次模拟比赛讲解已经结束,博主也是参考了https://blog.csdn.net/qq_44932745/article/details/129327344https://blog.csdn.net/m0_74183164/article/details/129453651

两篇博客加上自己的总结写出来的,如果有说明疑惑或者更优的方法可以评论或者私信。

  • 7
    点赞
  • 35
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Cocobol0

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值