片头
嗨~小伙伴们,今天咱们来看看填空题,蓝桥杯竞赛体型分为填空题和编程题。咱们先把填空题做对了,越往后面越有信心,对不对~
第1题 握手问题
分析这道题,我们有2种解题思路:
①编号1~7的人彼此之间不握手,但是这7个人与除这7人以外的所有人握手,剩下的所有人都与除自己以外的所有人进行握手(有且仅有1次)
②计算50个人彼此握手的次数-7个人相互握手的次数
方法一:
//①握手问题
//方法一
int main1() {
int count = 0;
for (int i = 1; i <= 50; i++) {
for (int j = i + 1; j <= 50; j++) {
//i和j表示我枚举的2个人,当2个人编号中至少1个人大于7时,才会握手
if (i <= 7 && j <= 7) continue;
else count++;
}
}
cout << count << endl; //1204
return 0;
}
方法二:采用等差数列求和
比如:这里有3个人,3号,2号,1号。
3号可以和2号握手,3号也可以和1号握手。2号可以和1号握手,总共2+1=3次。这时,如果来了4号,4号和3号握手,4号和2号握手,4号和1号握手,又增加了3次,总共3+2+1=6次。
那么,如果有50个人,
50号可以握49次,
49号可以握48次,
48号可以握47次,
........
3号可以握2次,
2号可以握1次,
1号可以握0次。
总共 49+48+47+46+.....+3+2+1+0 = (49+0)×50÷2 = n*(n-1)/2
代码如下:
//等差数列
int F(int n) {
return n * (n - 1) / 2;
}
int main() {
int ret = F(50) - F(7);
cout << ret << endl; //1204
return 0;
}
第2题 门牌制作
我们可以先定义一个for循环,遍历从1~2020之间的所有数字,统计每个数字中,"2"的出现次数。
代码如下:
//②门牌制作
int main() {
int count = 0; //计数器,用于统计字符"2"的个数
//遍历从1~2020的所有门牌号
for (int i = 1; i <= 2020; i++) {
int x = i;
//逐个提取数字并检查是否为"2"
while (x > 0) {
if (x % 10 == 2) count++; //如果当前数字为"2",计数器+1
x = x / 10; //去掉最后一位
}
}
cout << count << endl; //624
return 0;
}
第3题 幸运数
这道题,让我们判断这个数字是否为幸运数。幸运数——一个数含有偶数个数位,如果前面一半的数位之和等于后面一半的数位之和,那么这个数就是幸运数。题目要求从1~100000000之间有多少这样的数字。
首先,我们可以将1~100000000之间,排除非偶数个位的数。怎么排除呢?可以先将当前这个数字转换为字符串,求字符串的长度。如果长度为奇数,直接跳过当前循环,继续下一个循环。
如果长度为偶数,那么我们需要判断前一半的数是否等于后面一半的数,如果相等,则为幸运数。
代码如下:
//③幸运数-循环
int main() {
int count = 0;
for (int i = 1; i <= 100000000; i++) {
string x = to_string(i); //先将数字转换为字符串
int len = x.size(); //求字符串的长度
if (len % 2 == 1) continue; //如果这个长度为奇数,说明当前这个数非偶数个位
int sum1 = 0, sum2 = 0; //sum1表示前半部分的和,sum2表示后半部分的和
for (int j = 0; j < len; j++) {
if (j < len / 2) sum1 += x[j] - '0';
else sum2 += x[j] - '0';
}
if (sum1 == sum2) count++;
}
cout << count << endl; //4430091
return 0;
}
第4题 九进制转十进制
对于这道题,我们可以使用python来做,因为是填空题,所以不需要我们写出解答过程,只需填上最后的答案即可。
print(int('2022',9))
运行结果为:
1478
那么将九进制转换为十进制我们知晓了,怎么将十进制转换为二进制呢?
先来一个套公式:
n = 2022
print(format(n,"b")) #"b"代表的是: 以二进制的形式打印
运行结果为:
11111100110
我们再来自主实现:
s1 = ""
n = 2022
while(n > 0):
r = n % 2
s1 = str(r) + s1
n = n // 2
print(s1)
同理,将十进制转换为九进制就是依葫芦画瓢啦~
s = ""
num = 1478
while(num > 0):
r = num % 9 //转换为九进制
s = str(r) + s
num = num // 9
print(s)
运行结果如下:
2022
第5题 艺术与篮球
①对于这道题,我们可以先用数组cnt[10]把汉字零~九的笔画数存起来;定义数组month[13],用来存放每个月的天数(多开1个空间,方便计算);定义判断是否为闰年的函数bool is_leap(int y),如果当前年份为闰年,返回true,否则返回false
//从1月~12月,每个月的天数
int month[13] = { 0,31,28,31,30,31,30,31,31,30,31,30,31 };
int cnt[10];
//从零~九,每个汉字的笔画数
cnt[0] = 13, cnt[1] = 1, cnt[2] = 2, cnt[3] = 3, cnt[4] = 5;
cnt[5] = 4, cnt[6] = 4, cnt[7] = 2, cnt[8] = 2, cnt[9] = 2;
//判断闰年
bool is_leap(int y) {
if (y % 400 == 0 || (y % 4 == 0 && y % 100 != 0)) return true;
return false;
}
②定义3个变量y、m、d,分别表示年、月、日。年的范围是从2000年~2024年。因此,最外层的for循环从2000开始,到2024结束。
int res = 0;//统计可以练篮球的天数
int y, m, d;//分别表示年、月、日
//枚举年份
for (y = 2000; y <= 2024; y++) {
}
③接着需要判断月份的范围,题目已知,在2024年,月份只能到4月,因此,当y==2024时,月份的范围:1~4,上限为4;除此之外,月份的范围:1~12,上限为12。那么我们需要定义三元运算符,如果此时在2024年,那么月份的范上限为4,否则月份的上限为12。
int up1 = (y == 2024) ? 4 : 12;
④判断完月份取值范围后,咱们需要判断当前年份是否为闰年,如果此时为闰年,那么month数组里面表示2月份的天数修改为29天;如果不是闰年,2月份的天数仍然为28天。
//判断闰年
bool is_leap(int y) {
if (y % 400 == 0 || (y % 4 == 0 && y % 100 != 0)) return true;
return false;
}
if (is_leap(y)) month[2] = 29;
else month[2] = 28;
⑤根据前面月份的上限,我们开始循环遍历月份,题目已知:当年份为2024年并且月份为4月时,日期只能到13号,范围:1~13;除此以外,每个月的日期都可以用month数组里面的值来表示。我们可以用三元运算符来判断,当 y==2024 && m == 4 时,日期的上限为13;否则日期上限为month[m](m表示当前的月份)
//枚举年份
for (y = 2000; y <= 2024; y++) {
int up1 = (y == 2024) ? 4 : 12;
if (is_leap(y)) month[2] = 29;
else month[2] = 28;
//枚举月份
for (m = 1; m <= up1; m++) {
int up2 = (y == 2024 && m == 4) ? 13 : month[m];
}
}
⑥根据前面日期的上限,我们开始循环遍历日期,判断每一个日期是否符合笔画数>50。如果符合,计数器+1。
int res = 0;//统计可以练篮球的天数
int y, m, d;//分别表示年、月、日
//枚举年份
for (y = 2000; y <= 2024; y++) {
int up1 = (y == 2024) ? 4 : 12;
if (is_leap(y)) month[2] = 29;
else month[2] = 28;
//枚举月份
for (m = 1; m <= up1; m++) {
int up2 = (y == 2024 && m == 4) ? 13 : month[m];
//枚举日期
for (d = 1; d <= up2; d++) {
res += Func1(y, m, d);
}
}
}
⑦在main函数外面定义统计汉字笔画数的函数。我们可以把传递过来的年、月、日都转换为字符串,利用to_string函数。如果月份<10,那么需要加上字符'0',再和前面的年份拼接;如果日期<10,需要加上字符'0',再和前面的年份、月份进行拼接。拼接完成后,使用范围for循环遍历字符串中每一个元素,计算每一个元素在cnt数组中的映射位置对应的值。用变量res统计每一个字符串类型的日期总笔画数。返回总笔画数>50的结果。如果总笔画数>50,返回1;否则返回0。
int Func1(int y, int m, int d) {
string s = to_string(y); //将年份转换为字符串
if (m < 10) s += '0';
s += to_string(m); //将月份转换为字符串并且和年份拼接
if (d < 10) s += '0';
s += to_string(d); //将日期转换为字符串并且和年份、月份拼接
int sum = 0;
for (auto e : s) //遍历s字符串中每一个元素
//找到cnt数组中的映射位置的值
{
sum += cnt[e - '0'];
}
return sum > 50; //返回结果
//如果大于50,return 1;否则 return 0;
}
欧克欧克,这道题整体代码如下:
//⑤艺术与篮球
int cnt[10];
//判断闰年
bool is_leap(int y) {
if (y % 400 == 0 || (y % 4 == 0 && y % 100 != 0)) return true;
return false;
}
int Func1(int y, int m, int d) {
string s = to_string(y); //将年份转换为字符串
if (m < 10) s += '0';
s += to_string(m); //将月份转换为字符串并且和年份拼接
if (d < 10) s += '0';
s += to_string(d); //将日期转换为字符串并且和年份、月份拼接
int sum = 0;
for (auto e : s) //遍历s字符串中每一个元素
//找到cnt数组中的映射位置的值
{
sum += cnt[e - '0'];
}
return sum > 50; //返回结果
//如果大于50,return 1;否则 return 0;
}
int main() {
//从1月~12月,每个月的天数
int month[13] = { 0,31,28,31,30,31,30,31,31,30,31,30,31 };
//从零~九,每个汉字的笔画数
cnt[0] = 13, cnt[1] = 1, cnt[2] = 2, cnt[3] = 3, cnt[4] = 5;
cnt[5] = 4, cnt[6] = 4, cnt[7] = 2, cnt[8] = 2, cnt[9] = 2;
int res = 0;//统计可以练篮球的天数
int y, m, d;//分别表示年、月、日
//枚举年份
for (y = 2000; y <= 2024; y++) {
int up1 = (y == 2024) ? 4 : 12;
if (is_leap(y)) month[2] = 29;
else month[2] = 28;
//枚举月份
for (m = 1; m <= up1; m++) {
int up2 = (y == 2024 && m == 4) ? 13 : month[m];
//枚举日期
for (d = 1; d <= up2; d++) {
res += Func1(y, m, d);
}
}
}
cout << res << endl; //3228
return 0;
}
运行结果为:
第6题 求和
这道题,我们可以运用高斯定理:(首项+末项)×项数÷2
#include <iostream>
using namespace std;
long long Func(long long n) {
return n * (n + 1) / 2;
}
int main() {
long long ret = Func(20230408);
cout << ret << endl;
return 0;
}
注意:这里的数据类型必须是长整型long long,如果为int,会溢出!
第7题 3个1
这道题,涉及到位运算相关知识。
我们从1开始遍历,终止条件未知,判断完这个数自动+1。
怎么判断1个数转换为二进制后,有3个数位为1呢?可以采用while循环,使这个数和1进行按位与&操作。按位与:两者相同为1,两者相异为0。
从右往左依次和1进行按位与&操作 ----> 判断完最后1个数位,再进行右移>>操作,判断倒数第2个数位,再判断倒数第3个数位.......,直到这个数为0,结束循环。
如果和1进行按位与&操作得出来的结果为1,计数器+1。
定义变量ans,当计数器恰好等于3时,ans++; 当ans恰好等于23时,将答案输出即可。
int main() {
int ans = 0;
for (int i = 1; ; i++) //起始条件: i = 1,从1开始往后遍历
//更新条件: 每判断完1个数,自动往后+1
{
int x = i; //将i的值赋给临时变量x
int count = 0; //count统计当前这个数的二进制中,出现"1"的次数
while (x > 0) //当x为0时,结束循环
{
if (x & 1) //将这个数和1进行按位与&操作
{
count++; //假设结果为1,count自增1
}
x = x >> 1; //每判断完最后1位,向右移,将最后1个数位覆盖掉
}
if (count == 3) ans++; //如果count的值为3,ans++
if (ans == 23) //如果此时ans为23,
//说明我们已经找到了第23个满足:
//数转换为二进制之后,恰好有3个数位为"1"
{
cout << i << endl; //将这个数输出
break; //终止循环
}
}
return 0;
}
第8题 美丽的2024
这道题和刚刚那道题差不多,只不过是统计二进制中"1"的个数。
代码如下:
//⑧美丽的2024-位运算
int main() {
int n = 2024;
int temp = n; //将n的值赋给临时变量
int cnt = 0; //统计二进制中,出现"1"的个数
while (temp > 0) //当temp==0时,终止循环
{
if (temp & 1) cnt++; //如果当前数位和1进行按位与&操作后,结果为1,cnt++;
temp = temp >> 1; //每操作完最后1个数位,向右移,将最后1个数位覆盖掉
}
cout << cnt << endl; //7 --> 11111101000
return 0;
}
第9题 跑步
诶,这道题,乍一看,感觉不复杂,咱们一起来看看~
我们首先定义月份数组month[13],用来统计每个月的天数。
外层for循环,表示月份范围,从1月到12月,内层for循环,表示日期,从1到month[i]。如果日期为1号、11号、21号、31号,那么计数器+1。
如何统计周六、周天呢?很简单,定义变量week,初始值为6,表示周六,如果 (week+1)%7==0,表示周天。那么,如果week==6或者week==0,计数器也要+1。
代码如下:
int main() {
int month[13] = { 0,31,28,31,30,31,30,31,31,30,31,30,31 };
int w = 6; //今天是星期六
int cnt = 0;
//枚举月
for (int i = 1; i <= 12; i++) {
//枚举日期
for (int j = 1; j <= month[i]; j++) {
//判断是否符合题目要求
if (w == 6 || w == 0 || j == 1 || j == 11 || j == 21 || j == 31) {
cnt++;
}
w = (w + 1) % 7; //如果周天+1,即周一,因此这里其实是循环的
}
}
cout << cnt << endl;
return 0;
}
片尾
今天我们学习了C++蓝桥杯填空题相关知识点,希望对友友们有所帮助!!!
求点赞收藏加关注!!!
谢谢大家!!!