第十届蓝桥杯C/C++ B组题目解析及参赛感受

首先,因为是第一次参赛(我们学校比较坑,大一不能参赛),所以以前不是很了解蓝桥杯的题目模式。随着做了几年的真题,发现蓝桥杯似乎有一种暴力求解的魔力,很多题目都可以通过暴力求解,例如第七届的第7题的剪邮票。所以又称为暴力杯,但是第九届的题目又有点难度,所以心中还是对蓝桥杯的难度存在疑虑。

最后及其不幸的是,第十届的蓝桥杯题目不是很难,填空题基本没有难度,编程题“看上去”也不是很难,然后。。我就理所当然的GG了,拿了个省二就当作陪跑了。。(很沮丧,其实算了分数就差一点)。

第一题:

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

 分析:这题用暴力可以做,但是数据量不大,手算花不了多久就能计算出来,并且可以验证最优解。

答案:490

第二题:年号字串

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

分析:这题也是可以手算的,因为他是特殊的26进制(不是0-25,而是1-26),所以需要注意的就是边界的进位。

答案:BYQ

第三题:数列求值

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

分析:这题注意每算完一项就对10000取模,就可以顺利得到答案。

代码:

#include 
using namespace std;

const int N = 3*1e7+5;
const int mod = 1e4;
int f[N];

int main()
{
	f[1] = f[2] = f[3] = 1;
	for(int i = 4; i <= 20190324; i++)
		f[i] = ((f[i-3]+f[i-2])%mod+f[i-1])%mod;
	cout << f[20190324];
}

 答案:4659

第四题:数的分解

把2019 分解成3 个各不相同的正整数之和,并且要求每个正整数都不包含数字 2 和 4,一共有多少种不同的分解方法?
注意交换3个整数的顺序被视为同一种方法,例如1000+1001+18 和 1001+1000+18 被视为同一种。

分析:这道题注意i

代码:

#include 
using namespace std;

const int N = 2500;
int a[N], vis[N];
int n, k, ans;

int check(int n)
{
	while(n >= 1)
	{
		if(n%10 == 2 || n%10 == 4)
			return 0;
		n /= 10;
	}
	return 1;
}
void DFS(int pre, int cur, int sum)
{
	if(cur == 3 && sum == n)
	{
		ans++;
		return;
	}
	if(cur >= 3)	return;
	for(int i = pre+1; i < k; i++)
	{
		if(!vis[a[i]])
		{
			vis[a[i]] = 1;
			DFS(i, cur+1, sum+a[i]);
			vis[a[i]] = 0;
		}
	}
}
int main()
{
	ans = k = 0;
	for(int i = 1; i <= 2016; i++)
		if(check(i))
			a[k++] = i;
	cin >> n;
	DFS(-1, 0, 0);
	cout << ans;
}

第五题:迷宫

下图给出了一个迷宫的平面图,其中标记为1 的为障碍,标记为0 的为可以通行的地方。

010000
000100
001001
110000
迷宫的入口为左上角,出口为右下角,在迷宫中,只能从一个位置走到这个它的上、下、左、右四个方向之一。
对于上面的迷宫,从入口开始,可以按DRRURRDDDR 的顺序通过迷宫,一共10 步。其中D、U、L、R 分别表示向下、向上、向左、向右走。对于下面这个更复杂的迷宫(30 行50 列),请找出一种通过迷宫的方式,其使用的步数最少,在步数最少的前提下,请找出字典序最小的一个作为答案。请注意在字典序中D

分析:这道题BFS和DFS都可以,我用的是BFS,因为我DFS比较烂。。算是一道裸题吧,不难。

代码:

 

#include 
using namespace std;
struct node {
	int x, y;
	string p;
};
char s[35][55];
int vis[35][55], n, m;
char d[] = {'D', 'L', 'R', 'U'};
int dx[] = {1, 0, 0, -1};
int dy[] = {0, -1, 1, 0};
 
int check(int x, int y)
{
	if(x>=0 && x=0 && yq;
	q.push(node{x, y, ""});
	while(!q.empty())
	{
		now = q.front();
		q.pop();
		if(now.x == n-1 && now.y == m-1)
		{
			cout << now.p;
			exit(0);
		}
		for(int i = 0; i < 4; i++)
		{
			next = now;
			next.x += dx[i];
			next.y += dy[i];
			if(check(next.x, next.y))
			{
				vis[next.x][next.y] = 1;
				next.p += d[i];
				q.push(next);
			}
		}
	} 
}
int main()
{
	cin >> n >> m;
	for(int i = 0; i < n; i++)
		scanf("%s", s[i]);
	memset(vis, 0, sizeof(vis));
	vis[0][0] = 1;
	BFS(0, 0);
}
/*
4 6
010000
000100
001001
110000
*/
/*
30 50
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
*/

 答案:DDDDRRURRRRRRDRRRRDDDLDDRDDDDDDDDDDDDRDDRRRURRUURRDDDDRDRRRRRRDRRURRDDDRRRRUURUUUUUUULULLUUUURRRRUULLLUUUULLUUULUURRURRURURRRDDRRRRRDDRRDDLLLDDRRDDRDDLDDDLLDDLLLDLDDDLDDRRRRRRRRRDDDDDDRR

第六题:特别数的和

小明对数位中含有 2、0、1、9 的数字很感兴趣(不包括前导0),在1 到 40 中这样的数包括1、2、9、10 至 32、39 和 40,共 28 个,他们的和是 574。请问,在 1 到n 中,所有这样的数的和是多少?

【输入格式】
输入一行包含两个整数n。

【输出格式】
输出一行,包含一个整数,表示满足条件的数的和。

【样例输入】
40

【样例输出】
574

【评测用例规模与约定】
对于20% 的评测用例,1≤n≤10。
对于50% 的评测用例,1≤n≤100。
对于80% 的评测用例,1≤n≤1000。
对于所有评测用例,1≤n≤10000。
 

分析:这道题就是第四题的编程题,思路就跟第四题一样。

代码:

#include 
using namespace std;

int check(int n)
{
	while(n >= 1)
	{
		if(n%10==2 || n%10==0 || n%10==1 || n%10==9)
			return 1;
		n /= 10;
	}
	return 0;
}
int main()
{
	int n, sum = 0;
	cin >> n;
	for(int i = 1; i <= n; i++)
		if(check(i))
			sum += i;
	cout << sum;
}

第七题:完全二叉树的权值

给定一棵包含N 个节点的完全二叉树,树上每个节点都有一个权值,按从上到下、从左到右的顺序依次是A1​,A2​,...,AN​ ,如下图所示:
现在小明要把相同深度的节点的权值加在一起,他想知道哪个深度的节点权值之和最大?如果有多个深度的权值和同为最大,请你输出其中最小的深度。
注:根的深度是1。

【输入格式】
第一行包含一个整数N。
第二行包含N 个整数A1​,A2​,...,AN​

【输出格式】
输出一个整数代表答案。

【样例输入】
7
1 6 5 4 3 2 1

【样例输出】
2
 

分析:因为是完全二叉树,遍历每一层的和就行了,需要注意的一点是:在设置最大值初值时,不能设为0!因为有可能是负数。我比赛的时候就死在这里了,因为我已经形成习惯了。。也是因为这题无缘省一,很心疼。。

代码:

#include 
using namespace std;
typedef long long ll;
const ll MAXN = 1e5+5;
ll a[MAXN];

int main()
{
	int n, ans, d, ind;
	ll Max = -MAXN*MAXN, sum;
	ind = ans = d = 1;
	cin >> n;
	for(int i = 1; i <= n; i++)
		cin >> a[i];
	while(n)
	{
		sum = 0;
		for(int i = ind; i < 1< Max)
		{
			Max = sum;
			ans = d;
		}
		n -= ind;
		ind += 1<

第八题:等差数列

数学老师给小明出了一道等差数列求和的题目。但是粗心的小明忘记了一部分的数列,只记得其中N 个整数。
现在给出这N 个整数,小明想知道包含这N 个整数的最短的等差数列有几项?
【输入格式】
输入的第一行包含一个整数N。
第二行包含N 个整数A1​,A2​,...,AN(注意A1~AN并不一定是按等差数列中的顺序给出)

【输出格式】
输出一个整数表示答案。

【样例输入】
5
2 6 4 10 20

【样例输出】
10

【样例说明】
包含2、6、4、10、20 的最短的等差数列是2、4、6、8、10、12、14、16、18、20。

【评测用例规模与约定】
对于所有评测用例,2≤N≤100000, 0≤Ai≤10^9

分析:对所有数字排序,计算相邻的数的差,公差就是公共的差,由此可以想到GCD。

需要注意的是:d可能=0!这时候就是常数项,直接输出N即可。

代码:

#include 
using namespace std;

const int N = 1e5+5;
int a[N], d[N];

int gcd(int a, int b)
{
	return b == 0 ? a : gcd(b, a%b);
}
int main()
{
	int n, p, ans;
	cin >> n;
	for(int i = 0; i < n; i++)
		cin >> a[i];
	sort(a, a+n);
	for(int i = 1; i < n; i++)
		d[i-1] = a[i]-a[i-1];
	p = d[0];
	if(!p)	printf("%d", n);
	else
	{
		for(int i = 1; i < n-1; i++)
			p = gcd(p, d[i]);
		ans = (a[n-1] - a[0]) / p + 1;
		cout << ans;
	}
}

第九题:后缀表达式

给定N 个加号、M 个减号以及N + M + 1 个整数A1,A2,...,AM+N+1,小明想知道由这些组成的后缀表达式的值最大为多少?

本次大赛最坑的题目出现了!!!

很多人用贪心做,排序完把前面N+1个数加起来-后M个数。

但是

后缀表达式是可以在任意地方加括号的!

分析:如果没有减号,显而易见把所有数加起来,如果有减号,因为-(-)就等于-和+,-(-(-)等于+和-(这里的+指的是加上一个数的绝对值),所以如果有减号,最后就可以利用括号转换成一个减号。

代码:

#include 
using namespace std;
#define inf 0x3f3f3f3f
typedef long long ll;
const int N = 1e5+5;
int a[2*N+5];

int main() 
{
	int n, m, Min, Max;
    cin >> n >> m;
    Min = inf;
    Max = -inf;
    for (int i = 0; i <= n+m; i++) 
	{
        cin >> a[i];
        Min = min(Min, a[i]);
        Max = max(Max, a[i]);
    }
    ll ans = 0;
    if(m) 
	{
        for(int i = 0; i <= n+m; i++)
            ans += abs(a[i]);
        if(Min > 0) ans -= Min * 2;
        if(Max < 0) ans += Max * 2;
    }
    else for (int i = 0; i <= n+m; i++)
        ans += a[i];
    cout << ans << endl;
    return 0;
}

第十题:略略略。

你可能感兴趣的:(思维)