蓝桥杯2020年第十一届C/C++B组(第二次)省赛习题题解

目录

试题A.门牌制作(拆分数字)

试题 B 既约分数(gcd)

试题C 蛇形填数(数学)

试题D 跑步锻炼(模拟) 

试题E 七段码(图论+并查集)

 试题F:成绩统计(格式化输出)

 试题G:回文日期(模拟)

试题H:子串分值和(哈希+乘法原理+数学)

试题I:平面切分(数学)

 试题J:字串排序(dp)



试题来源:蓝桥杯2020第十一届C语言B组省赛习题题解_shall_zhao的博客-CSDN博客_蓝桥杯c语言题目


试题A.门牌制作(拆分数字)

 思路解析:遍历1~2020,统计每个数字中2的次数,运用到拆分数字的基本算法

#include<iostream>
using namespace std;

int cal(int num)
{
	int cnt = 0;
	while (num)
	{
		int j = num % 10;
		if (j == 2) cnt++;
		num /= 10;
	}
	return cnt;
}

int main()
{
	int res = 0;
	for (int i = 1; i <= 2020; i++)
	{
		res += cal(i);
	}

	cout << res << endl;//答案为624

	return 0;
}

试题 B 既约分数(gcd)

 思路解析:两层内外循环遍历1~2020,用欧几里得算法判断是否是两数的最大公约数为1,统计个数即可

#include<iostream>
using namespace std;

int gcd(int a, int b)
{
	return b ? gcd(b, a % b) : a;
}

int main()
{
	int res = 0;
	for(int i=1;i<=2020;i++)
		for (int j = 1; j <= 2020; j++)
		{
			if (gcd(i, j) == 1) res++;
		}
	cout << res << endl;//答案为:2481215

	return 0;
}

试题C 蛇形填数(数学)

问题: 根据此规律,推断第20行20列的数字是多少,其中第2行第2列的数字为5

 思路解析:

(1)对于奇数行有:比如说数字‘4’的那一行,则有:从它向它的右上角方向依次+1

(2)对于偶数行有:比如说数字‘10’的那一行,则有:从它向它的右上角方向依次-1

那么同理:

(3)对于奇数列有:比如说数字‘6’的那一列,则有:从它向它的左下角方向依次-1

(4)对于偶数列有:比如说数字‘7’的那一列,则有:从它向它的左下角方向依次+1

那么就有:

定义一个计数器cnt=1,循环for一次,同时枚举(i)行数和列数,如果这个(i)为奇数,那么就让它对应(1)情况,让它向右上角方向++;同理如果这个(i)为偶数,那么就让它对应(4)情况,让它向它的左下角方向++,其中是将cnt的值赋给这个二维数组,并++,最后输出对应行数和列数即可

#include<iostream>
using namespace std;
const int N = 110;
int a[N][N];

int main()
{
	int cnt = 1;
	int x, y;
	for (int i = 1; i <= N; i++)
	{
		if (i % 2 == 1)
		{
			for (x = i, y = 1; x >= 1 && y <= i; x--, y++)
			{
				a[x][y] = cnt++;
			}
		}
		else
		{
			for (x = 1, y = i; x <= i && y >= 1; x++, y--)
			{
				a[x][y] = cnt++;
			}
		}
	}
	cout << a[20][20] << endl;

	return 0;
}

试题D 跑步锻炼(模拟) 

问题:

 思路解析:

最外层循环枚举年份,接着二判断是否是闰年,如果是闰年,那么就让原先定义好的二月天数改为29,接着内循环枚举月份,接着内循环枚举月份中的天数,如果天数是1,或者为周一,那么就让sum+=2,否则则为普通日子:让sum+=1,枚举完一天后,让星期++,并对7取模,注意枚举该年份后,需要将2月的天数重新修改为28

#include<iostream>
using namespace std;

int months[13] = { 0,31,28,31,30,31,30,31,31,30,31,30,31 };
int main()
{
	int year1 = 2000, year2 = 2020;
	int month1 = 1, month2 = 10;
	int day1 = 1, day2 = 1;
	int week = 6;

	long long sum = 0;

	for (year1; year1 <= year2; year1++)
	{
		if ((year1 % 400 == 0) || (year1 % 4 == 0 && year1 % 100 != 0))
		{
			months[2] = 29;
		}
		for (int i = 1; i <= 12; i++)
		{
			for (int day = 1; day <= months[i]; day++)
			{
				if (day == 1 || week == 1)
				{
					sum += 2;
				}
				else
				{
					sum += 1;
				}
				week = (week + 1) % 7;
				if (year1 == 2020 && i == 10 && day == 1)
				{
					cout << sum << endl;//答案为:8879
					return 0;
				}
			}
		}
		months[2] = 28;
	}

	return 0;
}

试题E 七段码(图论+并查集)

 

 题目概述:

必须要相邻才能发光,也就是所有开着的灯必须是连通的,才能算是一种合法方案,求合法的方案数

#include<iostream>
using namespace std;

int use[10];
int ans, e[10][10], father[10];

void init()
{
    //连边建图
    //a b c d e f g
    //1 2 3 4 5 6 7
    e[1][2] = e[1][6] = 1;
    e[2][1] = e[2][7] = e[2][3] = 1;
    e[3][2] = e[3][4] = e[3][7] = 1;
    e[4][3] = e[4][5] = 1;
    e[5][4] = e[5][6] = e[5][7] = 1;
    e[6][1] = e[6][5] = e[6][7] = 1;
}

int  find(int a)
{
    //并查集
    return (a == father[a]) ? a : father[a] = find(father[a]);

}
void dfs(int d)
{
    if (d > 7)//一个七段管的所有灯的状态已经列举完了
    {
        for (int i = 1; i <= 7; i++)
        {
            father[i] = i;//初始化
        }
        for (int i = 1; i <= 7; i++)
        {
            for (int j = 1; j <= 7; j++)
            {//如果存在这条边 且 开i节点 且 开j节点
                if (e[i][j] && use[i] && use[j])
                {
                    int fa = find(i), fb = find(j);//寻找i,j对于的祖宗节点
                    if (fa != fb)//如果祖宗节点不同,证明未连通
                    {
                        father[fa] = fb;//连通 a b
                    }
                }
            }
        }

        int k = 0;
        for (int i = 1; i <= 7; i++)
        {
            if (use[i] && i == father[i])//如果它被用过 且 它等于它的祖宗节点
                k++;
        }
        if (k == 1)//只有一个父节点,就说明他们是相连的
            ans++;
        return;
    }

    use[d] = 0;//不选
    dfs(d + 1);

    use[d] = 1; //选
    dfs(d + 1);
    use[d] = 0;//归位
}
int main()
{
    init();
    dfs(1);
    cout << ans << endl;
    return 0;
}

 试题F:成绩统计(格式化输出)

 

格式化输出的陷阱://格式化输出%的陷阱:要输入%%才表示 %

#include<iostream>
using namespace std;
int main()
{
	int n;
	cin >> n;
	double a = 0;
	double b = 0;
	int x;
	for (int i = 1; i <= n; i++)
	{
		cin >> x;
		if (x >= 60) a++;
		if (x >= 85) b++;
	}
    //格式化输出%的陷阱:要输入%%才表示 %
	printf("%.0lf%%\n%.0lf%%", a / (n/100.0), b / (n/100.0));

	return 0;
}

 试题G:回文日期(模拟)

 

思路解析:

本题于与Acwing上的回文日期差不多   466. 回文日期 - AcWing题库

通过Acwing的这题,可以得到的经验是:遍历前四位数,然后进行回文构造,然后再判断构造出来的回文串是否满足日期的标准,即判断它是否是合法的日期,即可

先贴一下Acwing上的回文日期的答案:

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>

using namespace std;

int months[13] = { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };

bool check(int date)
{
    int year = date / 10000;
    int month = date % 10000 / 100;
    int day = date % 100;

    if (!month || month >= 13 || !day) return false;

    if (month != 2 && day > months[month]) return false;
    if (month == 2)
    {
        bool leap = year % 4 == 0 && year % 100 || year % 400 == 0;
        if (day > 28 + leap) return false;
    }

    return true;
}

int main()
{
    int date1, date2;
    cin >> date1 >> date2;

    int res = 0;
    for (int i = 1000; i < 10000; i++)
    {
        int x = i, r = i;//构造后四个:先构造回文串,再判断其是否合法
        for (int j = 0; j < 4; j++) r = r * 10 + x % 10, x /= 10;

        if (r >= date1 && r <= date2 && check(r)) res++;
    }

    printf("%d\n", res);
    return 0;
}

那么此题与Acwing上不同的地方在于:

输入是一个合法的八位数的日期

第一个输出是,这个日期之后的第一个合法的回文日期

第二个输出是,这个日期之后的第一个符合ABABBABA的日期

注意注释的一些细节即可

#include<iostream>
#include<cstdio>
using namespace std;

int months[13] = { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };

bool check(int date)//判断是否位合法日期
{
	int year = date / 10000;
	int month = date % 10000 / 100;
	int day = date % 100;

	//如果月份为0 || 月份大于等于13 || 日数为0
	if (!month || month >= 13 || !day) return false;

	//如果月份!=2   && 日数大于该月的天数
	if (month != 2 && day > months[month]) return false;
	if (month == 2)
	{
		bool leap = (year % 4 == 0 && year % 100 != 0) || (year % 400 == 0);
		if (day > 28 + leap) return false;//如果二月的天数>大于原本的二月天数+(可能的闰年+1的天数)
	}
	return true;
}

bool checkAB(int s)//判断AB
{
	bool flag = false;
	int y, m, d;
	y = s / 10000;   // 得到年份 
	m = (s / 100) % 100; // 得到月份  (BA)
	d = s % 100;  // 得到日  (BA)

	int k, n;
	k = y / 100;  // AB 
	n = y % 100; // AB 
	if (k == n && m == d)  // 判断是否为ABABBABA 
	{
		flag = true;
	}
	return flag;
}

int main()
{
	int date;
	cin >> date;

	int flag = 0;
	for (int i = (date/10000) +1; i <= 9999; i++)//枚举四位数的年份
	{		//举例 i=1234
		int left = i;
		int right = i;//构造出来的回文串,构造出来的回文串即:12344321
		for (int j = 0; j < 4; j++)
		{
			right = right * 10 + left % 10;//1234*10+1234%10
			left = left / 10;//得到left的下一位
		}//因为是按顺序进行的枚举,所以先符合条件的第一个必然是顺序最小的那一个
		if (check(right))
		{
			flag++;//保证第一个符合的回文串只有一个输出
			if (flag == 1) cout << right << endl;
			if (checkAB(right))
			{
				cout << right << endl;
				return 0;
			}
		}
	}
}

试题H:子串分值和(哈希+乘法原理+数学)

 (1)暴力思路解析:哈希表存储字母出现的次数,查看哈希表中是否有多个字母即可

最外层循环枚举一次走的步长

        第二层循环枚举左端点

                第三层循环将左端点~~~左端点+步长的这一段距离 赋值

                查找哈希表中是否存在元素,如果存在即 res++

                memset:重新初始化哈希表

cout<<res<<endl;

#include<iostream>
#include<algorithm>
#include<cstring>
#include<string>
using namespace std;

int main()
{
	string s;
	cin >> s;

	int n = s.size();
	int cnt[27] = { 0 };
	int res = 0;

	for (int len = 1; len <= n; len++)//枚举长度
	{
		for (int i = 0; i + len <= n; i++)//枚举左端点
		{
			for (int j = i; j < i + len; j++)//将该段进行填充
			{
				cnt[s[j] - 'a']++;
			}
			for (int k = 0; k < 26; k++)//查找
			{
				if (cnt[k] != 0) res++;
			}
			memset(cnt, 0, sizeof cnt);//重新赋值为:0
		}
	}

	cout << res << endl;

	return 0;
}


 (2)小优化:变成两层循环

#include<iostream>
#include<string>
#include<cstring>
using namespace std;

const int N = 10010;
char str[N];
bool st[26];

int main()
{
	scanf("%s", str + 1);
	int n = strlen(str + 1);

	long long ans = 0;
	for (int i = 1; i <= n; i++)
	{
		memset(st, 0, sizeof st);
		int t = str[i] - 'a';
		st[t] = true;
		int cnt = 1;
		ans += cnt;
		for (int j = i - 1; j >= 1; j--)
		{
			int t = str[j] - 'a';
			if (!st[i])
			{
				cnt++;
				st[t] = true;
			}
			ans += cnt;
		}
	}

	printf("%lld\n", ans);

	return 0;
}


 (3)大优化

第十一届蓝桥杯 ——子串分值和_六级不考550+不改名-CSDN博客

#include<iostream>
#include<cstring>
using namespace std;
typedef long long ll;
int last[127];

int main()
{
	string s;
	cin >> s;

	int n = s.size();
	s = ' ' + s;

	ll ans = 0;
	for (int i = 1; i <= n; i++)
	{
		ans += (ll)(i - last[s[i]]) * (n - i + 1);
		last[s[i]] = i;
	}

	cout << ans << endl;

	return 0;
}


试题I:平面切分(数学)

#include<iostream>
#include<set>
using namespace std;

typedef pair<double, double> pdd;
set<pdd> lines;
int res = 1;

int cmp(double c, double d)//求此条直线与之前所有直线的交点的个数
{
	set<pdd> points;
	pdd it;
	for (auto i = lines.begin(); i != lines.end(); i++)
	{
		double a = i->first;
		double b = i->second;
		if (a != c)//斜率不同,则两条直线不重合
		{
			it.first = (d - b) / (a - c);//求交点的横坐标
			it.second = c * it.first + d;//纵坐标
			points.insert(it);
		}
	}
	return points.size();
}

int main()
{
	int n;
	cin >> n;

	while (n--)
	{
		double a, b;
		cin >> a >> b;
		int count1 = lines.size();
		lines.insert({ a,b });
		if (lines.size() != count1)
		{
			res++;
			res += cmp(a, b);
		}
	}

	cout << res << endl;

	return 0;
}

 试题J:字串排序(dp)

在这里插入图片描述

 第十一届蓝桥杯——字串排序(DP)_Dripping Blog-CSDN博客_字串排序

  • 12
    点赞
  • 63
    收藏
    觉得还不错? 一键收藏
  • 6
    评论
蓝桥杯是一个国内著名的计算机比赛,为了帮助参赛者更好地准备和了解比赛的题型,委会会公布历的真题并提供相应的题解。 首先,我们需要了解蓝桥杯是一个综合性的计算机比赛,测试的对象包括计算机基础知识、编程能力以及解决实际问题的能力。 在历的真题中,参赛者将面临不同类型的题目,包括算法设计与优化问题、数据结构与算法问题、编程题等。其中针对Python B的题目主要考察的是对Python语言的掌握和应用能力。 题目解答一般会包含以下几个方面的内容: 1. 题目分析与理解:读取题目,理解题目的要求和限制条件。通过仔细分析题目,确定题目的输入与输出,以及问题的核心。 2. 设计解决方案:根据题目要求和限制条件,设计一个合适的解决方案。可以使用合适的算法和数据结构来解决问题,并做出相应的性能优化。 3. 编写代码实现:根据设计的方案编写相应的代码实现。需要注意的是,Python语言有其独特的语法和特性,掌握好这些特性可以更好地完成编程任务。 4. 调试与测试:编写完代码后,需要进行调试和测试。通过运行样例输入和输出,检查代码是否符合题目要求,并且没有逻辑上的错误。 5. 总结与优化:在完成题目解答后,可以进行总结和优化。包括分析算法复杂度、代码风格和可读性等方面,以便在比赛中更好地表现。 在准备蓝桥杯时,可以通过阅读历的真题和题解来了解比赛的难度和类型,针对性地进行练习和提高。同时也可以参加相关的培训班和讨论活动,与其他参赛者交流经验和技巧。 总而言之,历蓝桥杯真题的解答对于提高自己的编程能力和应对比赛非常有帮助。通过认真分析和实践,可以更好地理解并掌握Python编程,并在比赛中取得更好的成绩。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值