蓝桥杯冲刺——第十二届蓝桥杯大赛软件赛省赛 C/C++ 大学 B 组

✅ 比赛前练练手的… 能拿下多少分是多少分



一、空间——[5 分]

在这里插入图片描述


1.1 解析

● 小蓝准备用 256MB内存空间 开了一个数组,即这个数组的 内存空间256 × 1024 × 1024 B,也即是 256 × 1024 × 1024 × 8 bit

● 而数组的每个元素都是 32 位,即 32 bit

● 如果不考虑程序占用的空间和维护内存需要的辅助空间,则 256MB 的空间可以存储多少个 32 bit 的数据呢?(题目中的 “二进制整数” 是干扰信息,不用多想)

● 即用 256 × 1024 × 1024 × 8 bit 除以 32 bit 即可。


1.2 答案

● 填空题答案:67108864



二、卡片——[5 分]

在这里插入图片描述


2.1 解析

● 这道题是一道打卡 模拟题

初始化:用一个长度为 10 的数组来装 0 ~ 910 种卡片,然后分别赋值 2021

● 接着 start_num 赋值为 1,开始从 1 处理,处理完后执行 start_num++

● 对每一个出现的 start_num,灵活运用 %\ 来分解一个数。比如将 703 分解为 7、0、3

注意细节:为什么在我的代码里,最后的答案要 -1,因为当 cnt[end] < 0 条件满足时,就已经说明这个 不能够用现有的卡片凑成了。故要 -1


2.2 答案

● 填空题答案:3181

计算机编程C++代码(参考)

#include<iostream>
#include<stdlib.h> 
using namespace std;
int cnt[10];
int main()
{
    
    
	int start_num = 1, flag = 1;
	for(int i = 0; i < 10; i++)
	{
    
    
		cnt[i] = 2021;
	}
	while(flag)
	{
    
    
		int tmp = start_num;
		while(tmp > 0)
		{
    
    	
			int end = tmp % 10;	// 取出这个数的个位 
			cnt[end]--;	
			if( cnt[end] < 0 )	// 卡片不够用了 
			{
    
    
				flag = 0;
				cout << "跳出循环已执行,且答案=" << start_num - 1 << endl;	 
				break;
			}
			tmp = tmp / 10;
		}
		start_num++;
	}
	system("pause");
	return 0;
}


三、直线——[10 分]

在这里插入图片描述


3.1 解析

● 这道题也是一道 模拟题

● 依次遍历 “第一个点 A ( x 1 , y 1 ) (x1,y1) (x1,y1)” 和 “第二个点 B ( x 2 , y 2 ) (x2,y2) (x2,y2)” 即可。其中 x ∈ [ 0 , 19 ] , y ∈ [ 0 , 20 ] x∈[0,19],y∈[0,20] x[0,19]y[0,20]

● 在遍历中,每生成一对新的 A 和 B,我们要去计算连接 A 和 B 的直线的 斜率k截距b。如果得到的这一对 (k,b) 从未出现过,则答案数 +1,否则跳过忽略开始遍历下一对新的 A 和 B。

● 由高中知识可知: 若 y = k × x + b , 则 k = y 1 − y 2 x 1 − x 2 , b = y 1 − k × x 1 若 y=k\times x + b,则k = \frac{y1-y2}{x1-x2},b=y1-k\times x1 y=k×x+bk=x1x2y1y2b=y1k×x1

● 然而,如果直接用 b=y1-k*x 来计算 b,会导致精度爆炸(即溢出)。故我们要进行简单地推导: b = y 1 − k × x 1 = y 1 − y 1 − y 2 x 1 − x 2 × x 1 = x 1 y 1 − x 2 y 1 − ( x 1 y 1 − x 1 y 2 ) x 1 − x 2 = x 1 y 2 − x 2 y 1 x 1 − x 2 b=y1-k\times x1=y1-\frac{y1-y2}{x1-x2} \times x1=\frac{x1y1-x2y1 -(x1y1-x1y2)}{x1-x2}=\frac{x1y2-x2y1}{x1-x2} b=y1k×x1=y1x1x2y1y2×x1=x1x2x1y1x2y1(x1y1x1y2)=x1x2x1y2x2y1

注意:存在 “竖直直线” 的情况,我们单独对其进行判断即可。

● 关于 “去重”,我们用 C++ 的 “集合set”,它自带去重功能。


3.2 答案

● 填空题答案:40257

#include<iostream>
#include<stdlib.h>
#include<set> 
using namespace std;
set< pair<double,double> > s1;	// 装一般情况(非竖直)的直线 
set<int> s2;	// 装竖直的直线 
int main()
{
    
    
	for(int x1 = 0; x1 < 20; x1++)
	{
    
    
		for(int y1 = 0; y1 < 21; y1++)
		{
    
    
			for(int x2 = 0; x2 < 20; x2++)
			{
    
    
				for(int y2 = 0; y2 < 21; y2++)
				{
    
    
					if(x1 == x2) // 说明是一条竖线
					{
    
    
						s2.insert(x1);
					} 
					else
					{
    
    
						double k = 1.0 * (y1 - y2) / (x1 - x2); 	// 斜率
						double b = 1.0 * (x1 * y2 - x2 * y1) / (x1 -x2); // 截距
						s1.insert({
    
    k,b}); 
					}
				}
			}
		}
	}
	cout << "答案为:" << s1.size() + s2.size(); 
	system("pause");
	return 0;
}


四、货物摆放——[10 分]

在这里插入图片描述


4.1 解析

● 我感觉我做复杂了。但总归做出来了,花了 1 个小时左右吧。

● 网上有巧妙的解法,直接穷举,但要讲究效率,因为题目中的 n 很大,2021041820210418 这么大,穷举得不好的话,一天都算不完。

我的方法:假设 n=24,那么我只向下分解两层 质因数对,注意是 “”,分解成一对一对的。显然 24 可以分解成 (2,12)(3,8)(4,6) ,那么 (2,12) 就和它上一层左边1 构成 (1,2,12) 就是一个排列方式,然后对其进行全排列,即可得到 6 种排列方式。

  而对于 (3,8) 也是一样大,它和上一层左边1 构成 (1,3,8) 也是一个排列方式,然后对其进行全排列,又得到 6 种排列方式。

  然后对于 “第2层”,12 分解成 (2,6) 时,那么 (2,6) 就和上一层左边2 构成 (2,2,6) 也是一个排列方式,然后对其进行全排列,又得到 3 种排列方式。

  在分解过程中要注意去重,这里我用的 c++ 的 集合set

  比如说,我为什么说第2层的 (2,4) 是重复的,因为它和上一层左边3 构成 (3,2,4) 本质上和 “第2层的 (3,4) 和上一层左边2 构成 (2,3,4)” 是一样的。

在这里插入图片描述


4.2 答案

● c++代码:

#include<iostream>
#include<stdlib.h>
#include<queue>
#include<set>
#include<algorithm>
using namespace std;
#define lld long long int

set< pair< pair<lld,lld>, lld> > s1;
queue< pair<lld,lld> > q1;
lld Calculate(lld x, lld y, lld z)	// 计算 x, y, z 的全排列有 ? 种 
{
    
    
	if(x == y && x == z)
		return 1;
	else if(x == y || x == z || y == z)
		return 3;  // 其中有两个相同
	else	
		return 6;	// 三个数都不一样 
}

lld mid(lld x, lld y, lld z)	// 计算三个数中, 值在中间的那个数
{
    
    
	if(y <= x && x <= z || z <= x && x <= y)
		return x;
	else if(x <= y && y <= z || z <= y && y <= x)
		return y;
	else if(x <= z && z <= y || y <= z && z <= x)
		return z;
}

int main()
{
    
    
	lld n =  2021041820210418;
	lld ans = 0;  // 装答案 
	int cnt = 2;  // 下沉次数 
	q1.push({
    
    1,n});
	while( cnt > 0 )
	{
    
    	
		cnt--;
		queue< pair<lld,lld> > q2;	// 临时队列
		for(lld i = 0; i < q1.size(); i++)
		{
    
    
			pair<lld,lld> tmp = q1.front();
			lld num_1 = tmp.first;	// 取出第一个数
			lld num_2 = tmp.second;	// 取出第二个数
			q1.pop();
			// 计算因数(除开1)
			for(lld j = 2; j * j <= num_1; j++)
			{
    
    
				if(num_1 % j == 0 && num_1 / j != 1) // 没有余数, 即能整除(且商不为1) 
				{
    
    
					 lld shang = num_1 / j;		// 取出商
					 q2.push({
    
    j, shang});
					 lld min_num = min(min(j,shang),num_2);
					 lld mid_num = mid(j,shang,num_2);
					 lld max_num = max(max(j,shang),num_2);
					 pair< pair<lld,lld>, lld> p = make_pair( make_pair(min_num,mid_num), max_num);
					 s1.insert(p);
				} 
			}
			// 计算因数(除开1)
			for(lld j = 2; j * j <= num_2; j++)
			{
    
    
				if(num_2 % j == 0 && num_2 / j != 1) // 没有余数, 即能整除(且商不为1) 
				{
    
    
					lld shang = num_2 / j;		// 取出商
					q2.push({
    
    j, shang});	
					lld min_num = min(min(j,shang),num_1);
					lld mid_num = mid(j,shang,num_1);
					lld max_num = max(max(j,shang),num_1);
					pair< pair<lld,lld>, lld> p = make_pair( make_pair(min_num,mid_num), max_num);
					s1.insert(p);
				} 
			}
		}
		q1 = q2;
	}
	set< pair< pair<lld,lld>, lld> >::iterator iter;
	for(iter = s1.begin(); iter != s1.end(); iter++)
	{
    
    
		pair<lld,lld> p = (*iter).first;
		lld num1 = p.first;
		lld num2 = p.second;
		lld num3 = (*iter).second;
		ans += Calculate(num1,num2,num3);	
	}
	cout << "答案为:" << ans + 3; // 最后要考虑 (1,1,n) 这种全排列的情况
	system("pause");
	return 0;
}


五、路径——[15 分]

在这里插入图片描述


5.1 解析

● 大概是用 最小生成树+辗转相除法 吧…没时间做了


5.1 答案

● 后面有空补充吧…



六、时间显示——[15 分]

在这里插入图片描述
补充:【样例输出 2】01:08:23


6.1 解析

● 理解清楚题意后,善用 \% 来依次处理输入的 time ,以便得到相应的 时、分、秒 即可。

● 另外,这道题目的小难点在于 “格式化输入输出”,即怎么打印出 01:08:23,而不是 1:8:23

● 复习一下 C 语言的 “格式化输出字符” 即可知道:

输出格式 功能
%3d 输出宽度为 3 位,如果不足 3 位,前面空格补齐(即右对齐)
%05d 输出宽度为 5 位,如果不足 5 位,前面 0 补齐
%-4d 输出宽度为 4 位,如果不足 4 位,后面空格补齐(即左对齐)
%.2f 小数点后只保留 2 位小数。
%6.3f 输出宽度为 6 位,且小数点后只保留 2 位小数。

6.1 答案

#include<iostream>
#include<cstdio>
using namespace std;
#define lld long long int
int main()
{
    
    
	lld t;
	cin >> t;
	t = t / 1000;			// 去掉毫秒
	t = t % (3600 * 24);	// 只去最后一天的时间
	int hour = t / 3600;
	int minute = t % 3600 / 60;
	int second = t % 3600 % 60;
	printf("%02d:%02d:%02d",hour,minute,second);
	return 0;
}


七、砝码称重——[20 分]

在这里插入图片描述


7.1 解析

集合set 具有 去重 功能,做这道题很适合。

集合s1 作为一个 “答案容器”,集合s2 作为一个 “临时容器”。详细过程见代码。


7.1 答案

c++代码

#include<iostream>
#include<set>
#include<algorithm> 
using namespace std;
#define lld long long int
set<int> s1;
int n;
lld ans;
int w;
int main()
{
    
    
	cin >> n;
	s1.insert(0);		// 一开始需要放一个 “重量为0的砝码”, 对于例题而言: 以便后续凑出 0 + 6 的情况
	set<int>::iterator iter;
	for(int i = 0; i < n; i++)
	{
    
    
		cin >> w;
		set<int> s2;
		for(iter = s1.begin(); iter != s1.end(); iter++)
		{
    
    
			int tmp = *iter;
			s2.insert(tmp + w);			// 砝码放在 左边
			s2.insert(abs(tmp - w));	// 砝码放在 右边
		}
		for(iter = s2.begin(); iter != s2.end(); iter++)
		{
    
    
			s1.insert( (*iter) );		// 把 s2 中 “新凑出来的重量” 全部装入 s1
		}
	}
	cout << s1.size() - 1;		// 最后要把 “重量为0的答案” 去掉
	return 0;
}

八、杨辉三角形——[20分]

在这里插入图片描述
补充:【评测用例规模与约定】对于 20% 的评测用例,1 ≤ N ≤ 10;对于所有评测用例,1 ≤ N ≤ 1000000000


8.1 解析

在这里插入图片描述

● 杨辉三角形,根据上图来找规律,然后用穷举法:用两个 vector 来模拟。但只能得一部分的分。


8.2 答案

● 只能获得 40 分的答案:【满分答案有点难想】

#include<iostream>
#include<vector>
using namespace std;
typedef long long int lld;
vector<lld> v1;
lld n;
lld ans;
int main()
{
    
    
	cin >> n;
	if(n == 1)
	{
    
    
		cout << 1;
		return 0;
	}
	ans++;
	v1.push_back(1);
	while(1)
	{
    
    
		vector<lld> v2;
		for(lld i = 0; i < v1.size(); i++)
		{
    
    
			if(i == 0)
			{
    
    
				ans++;
				v2.push_back(1);
			}
			else
			{
    
    
				ans++;
				if(n == v1[i-1]+v1[i])	// 如果符合要求
				{
    
    
					cout << ans;
					return 0;
				}
				v2.push_back(v1[i-1]+v1[i]);
			}
		}
		ans++;
		v2.push_back(1);
		v1 = v2;
	}
	return 0;
}

九、双向排序——[25分]

在这里插入图片描述


9.1 解析

● 没时间了… 用暴力的 sort 能凑合 60 分吧…


9.2 答案

#include<iostream>
#include<algorithm>
using namespace std;
int n,m,p,q;
int a[100005];
int cmp(int x, int y)
{
    
    
	return x > y;
}
int main()
{
    
    
	cin >> n >> m;
	for(int i = 0; i < n; i++)
	{
    
    
		a[i] = i+1;
	}
	while( m > 0 )
	{
    
    
		m--;
		cin >> p >> q;
		if(p == 0) 
		{
    
    
			sort(a, a+q, cmp);	// 逆排
		}
		else
		{
    
    
			sort(a+q-1, a+n);	// 正排
			
		}
	}
	for(int i = 0; i < n; i++)
		cout << a[i] << " ";
	return 0;
}

十、括号序列——[25分]

在这里插入图片描述

● 没时间了… 不写了…


猜你喜欢

转载自blog.csdn.net/Wang_Dou_Dou_/article/details/124042569
今日推荐