【蓝桥杯】第十届蓝桥杯软件类个人省赛C/C++B组

A:组队

问题

作为篮球队教练,你需要从以下名单中选出 1 号位至 5 号位各一名球员,组成球队的首发阵容。
每位球员担任 1 号位至 5 号位时的评分如下表所示。请你计算首发阵容 1 号位至 5 号位的评分之和最大可能是多少?
在这里插入图片描述

解答

手算,1-5号位分别选编号 17,20,15,11,18 球员。
结果 490


B:年号字串

问题

小明用字母A 对应数字1,B 对应2,以此类推,用Z 对应26。对于27以上的数字,小明用两位或更长位的字符串来对应,例如AA 对应27,AB 对应28,AZ 对应52,LQ 对应329。
请问2019 对应的字符串是什么?

解答

手算可推出 AA为27,AZ为52, ZZ 为 702,AAA为703,AZZ为1378,BZZ为2054。
得出2019为 BYQ


C:数列求值

问题

给定数列1, 1, 1, 3, 5, 9, 17, …,从第4 项开始,每项都是前3 项的和。求
第20190324 项的最后4 位数字。

解答

先将前三个数初始化,再使用for循环,上代码

代码

int main()
{
	vector<int> num={1,1,1}; 
	for(int i=3;i<20190324;i++)
	{
		int a=(num[i-3]+num[i-2]+num[i-1])%10000;
		if(i==20190323)
			printf("%d",a);
		num.push_back(a);
	}
	return 0;	
} 

答案

结果:4659
在这里插入图片描述

D:数的分解

在这里插入图片描述

解题思路

本题的要求需要注意一下几点

  1. 3个数各不相同
  2. 交换顺序视为同一种
  3. 分解出来的数中不能有2和4
  • 第一点和第二点可以用暴力循环解决,三重循环i,j,k,但循环的开始条件,每一个数设置比前一个数大 1,这样3个数不会相同,也不会产生交换顺序后出现重复的 3 个数。最后一层循环判断 i+j+k==2019
  • 最后一层循环中,判断 i ,j ,k中是否含有2和4

代码

#include<cstdio>
using namespace std;
//判断是否含有2和4的函数
bool judge(int i)
{
	int flag=true;
	while(i>0)
	{
		int k=i%10;
		if(k==2||k==4){
			flag=false;
			break;
		}
		i/=10;	
	}
	return flag;	
} 

int main(){
	int num=0;
	for(int i=1;i<2019;i++)
	{
		for(int j=i+1;j<2019;j++)
		{
			for(int k=j+1;k<2019;k++)
			{
				if(i+j+k==2019)
				{
					if(judge(i)&&judge(j)&&judge(k))
						num++;
				}	
			} 
		}
	}
	printf("%d",num);
	return 0;
}

答案

结果为 40785
在这里插入图片描述


E:迷宫

在这里插入图片描述
01010101001011001001010110010110100100001000101010
00001000100000101010010000100000001001100110100101
01111011010010001000001101001011100011000000010000
01000000001010100011010000101000001010101011001011
00011111000000101000010010100010100000101100000000
11001000110101000010101100011010011010101011110111
00011011010101001001001010000001000101001110000000
10100000101000100110101010111110011000010000111010
00111000001010100001100010000001000101001100001001
11000110100001110010001001010101010101010001101000
00010000100100000101001010101110100010101010000101
11100100101001001000010000010101010100100100010100
00000010000000101011001111010001100000101010100011
10101010011100001000011000010110011110110100001000
10101010100001101010100101000010100000111011101001
10000000101100010000101100101101001011100000000100
10101001000000010100100001000100000100011110101001
00101001010101101001010100011010101101110000110101
11001010000100001100000010100101000001000111000010
00001000110000110101101000000100101001001000011101
10100101000101000000001110110010110101101010100001
00101000010000110101010000100010001001000100010101
10100001000110010001000010101001010101011111010010
00000100101000000110010100101001000001000000000010
11010000001001110111001001000011101001011011101000
00000110100010001000100000001000011101000000110011
10101000101000100010001111100010101001010000001000
10000010100101001010110000000100101010001011101000
00111100001000010000000110111000000001000000001011
10000001100111010111010001000110111010101101111000

在这里插入图片描述

解题

本题是经典点迷宫问题,使用一个二维数组表示迷宫,一个二维数组记录每一步走的路径。

  • 因为是求最短路径,所以采用BFS,借助队列来遍历迷宫。
  • 要求步数最少前提下,字典序最小,字典序D<L<R<U,所以在BFS时在每一个结点处,按 下左右上 的顺序先后试探相邻节点并且入队(队列具有先进先出的特性)
  • 每入队一个节点表示通过该节点,需要将这个节点在二维数组中设置为不可通行
    迷宫在BFS遍历时的越界判断和障碍判断比较简单

代码

#include<cstdio>
#include<vector>
#include<queue>
#include<stack>
using namespace std;

const int N = 55;
int n=30,m=50;
bool vis[N][N];	//二维数组表示迷宫 
int rec[N][N];	//记录走过的路径 

struct node{	//表示迷宫中一个位置的结构体 
	int x;
	int y;
};
/*设置方向数组
因为相同长度需要字典序最小的方案
D<L<R<U
所以在BFS时在每一个结点处,按 下左右上 的顺序先后试探入队 
pos[0]表示向下
pos[1]表示向左
pos[2]表示向右
pos[3]表示向上
 */
struct POS{
	int x,y;
}pos[4]={{1,0},{0,-1},{0,1},{-1,0}};
//char dir[4]={'D','L','R','U'};

void bfs();
void print_path();

int main()
{
	int x;
	for(int i=0;i<30;i++)
	{
		for(int j=0;j<50;j++)
		{
			x=getchar()-'0';
			if(x==1) vis[i][j]=true;	//1表示障碍,不能走	
		}
		getchar();	//读取换行符 
	}
	bfs();
	print_path();
	//dfs(n-1, m-1);
	return 0;
}

void bfs()
{
	node tmp;
	queue<node> q;	//存储结点的队列
	
	q.push({0,0});	
	vis[0][0]=true; //初始将0,0结点入队,并且设置0,0位置不可通行
	
	while(!q.empty()){
		node p = q.front();
		q.pop();	//取队首元素,并将队首元素出队
		
		if(p.x==n-1&&p.y==m-1)	//??	
			return;	
			
		for(int i=0;i<4;i++)
		{
			tmp.x=p.x+pos[i].x;
			tmp.y=p.y+pos[i].y;	
			if(tmp.x<0||tmp.x>=n||tmp.y<0||tmp.y>=m||vis[tmp.x][tmp.y])	//越界和障碍判断 
				continue;
			//如果没有越界并且没有障碍
			q.push(tmp);
			vis[tmp.x][tmp.y]=true;
			rec[tmp.x][tmp.y]=i;	//记录路径				
		}	 
	} 	
}
//从出口反向寻找路径 
void print_path()
{
	int x=n-1;
	int y=m-1;
	stack<char> st;
	int direction;
	//从出口反向查找路径,并用栈记录路径方向 
	while(x!=0||y!=0)
	{
		direction=rec[x][y];
		if(direction==0){
			st.push('D');
			x=x-1;
		}else if(direction==1){
			st.push('L');
			y=y+1;
		}else if(direction==2){
			st.push('R');
			y=y-1;
		}else if(direction==3){
			st.push('U');
			x=x+1;
		}
	}
	//输出栈中方向
	while(!st.empty()){
		printf("%c",st.top());
		st.pop();
	} 
}
//void dfs(int x,int y){
//	if(x==0 && y==0) return;
//	dfs(x-pos[rec[x][y]].x,y-pos[rec[x][y]].y);
//	printf("%c", dir[rec[x][y]]);
//}

答案

DDDDRRURRRRRRDRRRRDDDLDDRDDDDDDDDDDDDRDDRRRURRUURRDDDDRDRRRRRRDRRURRDDDRRRRUURUUUUUUULULLUUUURRRRUULLLUUUULLUUULUURRURRURURRRDDRRRRRDDRRDDLLLDDRRDDRDDLDDDLLDDLLLDLDDDLDDRRRRRRRRRDDDDDDRR


F:特别数的和

在这里插入图片描述

题解

直接遍历加上一个判断函数。

代码

#include<cstdio>
using namespace std;

bool judge(int n)
{
	int flag = false;
	while(n>0)
	{
		int k=n%10;
		if(k==2||k==0||k==1||k==9)
		{
			flag=true;
			break;
		}
		n=n/10;
	}
	return flag;
}
int main(){
	int n=0;
	int sum=0;
	scanf("%d",&n);
	for(int i=1;i<=n;i++)
	{
		if(judge(i)) sum+=i;
	}
	printf("%d",sum);
	return 0;
}

G:完全二叉树的权值

在这里插入图片描述
在这里插入图片描述

题解

本题粗看以为是二叉树的题,可能需要构建二叉树,细看只是一道普通的算术题。
求每一层和的最大值,先输入个数n后,循环从键盘输入其他数字,大循环里面套一个每层的循环,初始第一层设置长度为1,每过一层长度乘2,用max记录 权和 最大值,当某一层的和 大于max时更新max

代码

#include<cstdio>
#include<limits.h> 
using namespace std;
typedef long long LL;

int main()
{
	int num = 0;
	scanf("%d",&num);
	LL max = INT_MIN;	//INT_MIN是在limits.h头文件中,代表INT型最小值 ,这里记录权值和最大 
	
	int grade=1;	//初始化为第一层 
	int max_grade=0; 
	for(int i=0,length=1;i<num;length*=2)
	{
		LL sum=0;
		for(int j=0;j<length;j++,i++)
		{
			int n=0;
			scanf("%d",&n);
			sum+=n;
		}
		if(sum>max)
		{
			max=sum;
			max_grade=grade;
		}	
		grade++;	
	}
	printf("%d",max_grade);
	return 0;
}

H:等差数列

在这里插入图片描述
在这里插入图片描述

题解

本题给定一个数列,求其完整的最短等差数列长度。
简单来说就是求公差,那么公差是多少,先将不完整的数列由小到大排序,我的思路是,将排序后的数列相邻两项相减,得到一个差值的数列。
那么最终的公差只可能比最小的差值还小或者相等,其实公差应该就是这些所有差值的最大公因数。例如数列 1 3 6 9 11,差值分别为 2 3 3 3,最小差值为2,公差不是最小差值2,因为差值 3不是 2的倍数,公差是 2 和 3 的最大公因数 1,所以这个数列的公差是 1。
如果差值出现0,则表示公差为 0。等差数列长度为 num=输入数据的个数。
如果公差不等于0,长度为 (max-min)/公差+1

代码1

#include<cstdio>
#include<algorithm>
#include<cmath> 
using namespace std;
typedef long long LL;
int main(){
	int num=0;
	scanf("%d",&num);
	LL *arr = new LL[num];
	LL *interv = new LL[num-1];	//记录相邻两个数的差值 
	
	for(int i=0;i<num;i++)
	{
		scanf("%lld",&arr[i]);
	}
	sort(arr,arr+num);	//排序 
	LL minn=arr[0];		//最小值 
	LL maxx=arr[num-1]; //最大值 
	
	//将interv 数组填满 
	for(int i=0;i<num-1;i++)
	{
		interv[i]=arr[i+1]-arr[i];
	}	
	
	sort(interv,interv+num-1);	//将差值排序
	LL itv=interv[0];
	int flag = true;
	while(itv>0)
	{
		flag=true;
		for(int i=0;i<num-1;i++)
		{
			if(interv[i]%itv!=0){
				flag=false;
				break;
			}
		}
		if(flag==true)
			break;
		else
			itv--;
	}
	if(itv==0)
	{
		printf("%d",num);
	}else{
		printf("%lld",(maxx-minn)/itv+1);
	}
	return 0;
}

代码2,更简洁的解法

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int maxn = 1e5 + 5;
LL a[maxn];
//辗转相除求公因数
int gcd(int a, int b) {
	return b == 0 ? a : gcd(b, a % b);
}

int main() {
	int n;
	scanf("%d", &n);
	for (int i = 1; i <= n; i++) {
		scanf("%d", &a[i]);
	}
	sort(a + 1, a + n + 1);
	for (int i = 2; i <= n; i++) {
		a[i] -= a[1];
	}
	int d = a[2];
	for (int i = 3; i <= n; i++) {
		d = gcd(d, a[i]);
	}
	if (d == 0) {
		cout << n << endl;
	} else {
		cout << a[n] / d + 1 << endl;
	}
	return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值