2019年第十届蓝桥杯C/C++ B组省赛题解

试题A——组队

在这里插入图片描述
在这里插入图片描述
话说这道题目别看简单,其实还真有点坑点,不细心一点,必然会WA,我比赛的时候,可能脑子抽了算的一行的最大值,其实这一道题目是要你选出1 - 20个编号的球员中选出五个位置的人,使得1号位到5号位的最大值尽量大。就至关于求1号位到5号位每一列都最大的值。
在这里插入图片描述
492填上?那就WA了
能够看到咱们圈出的每个位置的最大值1号位和3号位还有4号位都是同一我的,这显然是错的。
因此有一个限制条件就是每一个人只能去一个位置而不是多个位置。
在这里插入图片描述
这道题目编程实现的话还不如直接算来的直接。
答案:490node

试题B——年号字串

在这里插入图片描述
这道题目实际就是一个将十进制转换为26进制,分析题目给的数据
A——1
1 * 26^0 = 1
Z——26
26 * 26^0 = 26
AA——27
1 * 26^1 + 1 * 26^0 = 26 + 1 = 7
AB——28
1 * 26^1 + 2 * 26^0 = 26 + 2 = 28
AZ——52
1 * 26^1 + 26 * 26^0 = 26 + 26 = 52
LQ——329
12 * 26^1 + 17 * 26^0 = 312 + 17 = 329
这样就能够推出来是10进制转换26进制了
而后咱们模拟将十进制转换为26进制便可,使用短除法,在逆序输出字符串便可。ios

#include <bits/stdc++.h>
using namespace std;

char str[27] = {0,'A','B','C','D','E','F','G','H','I','J','K'
   			,'L','M','N','O','P','Q','R','S','T','U','V',
   			'W','X','Y','Z'};

int main() {
   int num;
   string ans = "";
   scanf("%d", &num);
   while(num) {
   	ans += str[num % 26];
   	num /= 26;
   }
   for (int i = ans.size() - 1; i >= 0; i--) {
   	cout << ans[i];
   }
   return 0;
}

答案:BYQc++

试题C——数列求值

在这里插入图片描述
这道题目其实就是一道斐波那契数列变形,并且题目直接告诉你从第四项开始每一项等于前三项的和,那根本不用观察直接能够写出递推式:web

dp[i] = dp[i - 1] + dp[i - 2] + dp[i - 3] (i >=4)
//边界条件
dp[1] = dp[2] = dp[3] = 1

知道这个就能够很好的求出答案了。
可是这么大的数确定超出long long 了,咱们能够猜一下使用高精度?不用使用,对每一步mod10000便可获得正确答案,那么不少人会问每一步mod不会对结果有影响?
证实:
在这里插入图片描述
字写的有点丑,这样能够证实其实每一次加起来在mod10000和加起来所有mod10000结果相同,那么就好算了。算法

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int mod = 1e4;

LL dp[20190325];

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

答案:4659编程

试题D——数的分解

在这里插入图片描述
这道题目由于分解三个数而后不能重复,还有每一个数不包含2,4。其实这道题目不用搜索,枚举就能够了,可是重复状况怎么考虑?
咱们发现2019 = x + y + z
那么对于一组x,y,z三个数的位置不一样也算一种那么,对于x,y,z三个位置至关于有6种摆放位置,咱们只须要将枚举结果除以6便可获得答案。数组

#include <bits/stdc++.h>
using namespace std;

bool check(int x, int y, int z) {	//判断三个正整数中是否含2或4 
	int res = 0;
	while (x) {
		res = x % 10;
		if (res == 2 || res == 4) return false;
		x /= 10;
	} 
	while (y) {
		res = y % 10;
		if (res == 2 || res == 4) return false;
		y /= 10;
	}
	while (z) {
		res = z % 10;
		if (res == 2 || res == 4) return false;
		z /= 10;
	}
	return true;
}

int main() {
	int ans = 0;
	for (int a = 1; a < 2019; a++) {
		for (int b = 1; b < 2019; b++) {
			if (b == a) continue;		//a,b,c三个数不相同
			for (int c = 1; c < 2019; c++) {
				if (b == c || a == c) continue;
				if (a + b + c == 2019 && check(a, b, c)) ans++;
			} 
		}
	}
	cout << ans / 6 << endl;
	return 0;
}

由于是填空题,时间复杂度为2019^3,仍是要跑个10几秒的
答案:40785ide

试题E——迷宫

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
当时看到这道题目,欣喜若狂,由于我以前在刷蓝桥杯的题库的时候在算法提升里面刷到了这道题目,如出一辙,名字叫学霸的迷宫svg

其实这道题目看到最短路,最容易想到BFS(广搜),可是这道题目不是要你求最短路长度而是求出最短路的路径,提交一个字符串,其实别想差,最简单的就是将方向数组的每一步上,下,左,右,和D,U,L,R相对应,只须要在结构体中添加一个字符串记录便可。方向数组的顺序要按照字典序从小到大的顺序D,L,R,U来跑。函数

/* 测试数据 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 */
#include <bits/stdc++.h>
using namespace std;

char mp[30][50];	//地图
bool vis[30][50];	//标记该点是否走过
int dir[4][2] = {{1,0},{0,-1},{0,1},{-1,0}};	//方向数组按照下,左,右,上的顺序走
char dirc[4] = {'D','L','R','U'}; 
int n,m;  	//迷宫的行列

struct node{
	int x;	//横坐标 
	int y;	//纵坐标 
	int step;	//步数 
	string str;	//路径 
	node(int xx, int yy, int ss, string s) {	//构造函数 
		x = xx;
		y = yy;
		step = ss;
		str = s;
	}
}; 

queue<node> q; //建立队列

bool check(int x, int y) {	//判断是否越界以及是不是墙以及是否访问过了 
	if (x < 0 || x >= n || y < 0 || y >= m || vis[x][y] || mp[x][y] == '1') {
		return false;
	}
	return true;
}

void bfs(int x, int y) {
	q.push(node(x, y, 0, ""));
	vis[x][y] = true;
	while (!q.empty()) {
		node now = q.front();
		if (now.x == n - 1 && now.y == m - 1) {	//到达终点了 
			cout << now.str << endl;
			cout << now.step << endl;
			break;
		}
		q.pop();
		for (int i = 0; i < 4; i++) {
			int nx = now.x + dir[i][0];
			int ny = now.y + dir[i][1];
			if (check(nx, ny)) {
				q.push(node(nx, ny, now.step + 1, now.str + dirc[i]));
				vis[nx][ny] = true;
			}
		}
	}
} 

int main() {
	scanf("%d%d", &n, &m);
	for (int i = 0; i < n; i++) {
		scanf("%s", mp[i]);
	}
	bfs(0, 0);
	return 0;
}

答案:DDDDRRURRRRRRDRRRRDDDLDDRDDDDDDDDDDDDRDDRRRURRUURRDDDDRDRRRRRRDRRURRDDDRRRRUURUUUUUUULULLUUUURRRRUULLLUUUULLUUULUURRURRURURRRDDRRRRRDDRRDDLLLDDRRDDRDDLDDDLLDDLLLDLDDDLDDRRRRRRRRRDDDDDDRR

试题F——特别数的和

在这里插入图片描述
在这里插入图片描述
这道题目差很少是水题,没啥算法,直接枚举加check便可

#include <bits/stdc++.h>
using namespace std;

bool check(int x) {
	int res = 0;
	while (x) {
		res = x % 10;
		if (res == 0 || res == 1 || res == 2 || res == 9) return true;
		x /= 10;
	}
	return false;
}

int main() {
	int n;
	scanf("%d", &n);
	int ans = 0;
	for (int i = 1; i <= n; i++) {
		if (check(i)) {
			ans += i;
		}
	}
	cout << ans << endl;
	return 0;
}

7.试题G——彻底二叉树的权值

在这里插入图片描述
在这里插入图片描述
这道题目刚开始在考场上看到的时候觉得要构建一颗树的,哪知道也是水题
其实就是求每一层的和的最大值,至于最大值相同时输出最小的那一层,根本不要考虑,由于你找到最大值之后你就拿后面层数的权值和和最大值比较只要小于就不更新,那么层数也不会更新。这样就能够了,我是边输入,边处理的,由于是二叉树那么我除了第一层输入一个数,而后咱们将长度*2,那么长度就为2表明第二层须要输入2个数,而后每次边输入,边处理便可。彻底二叉树不是满二叉树,最后一层不必定满。

#include <bits/stdc++.h>

using namespace std;

typedef long long LL;

int main()
{
    int n;
    cin >> n;
    LL maxv = INT_MIN;	//INT_MIN是在limits.h头文件中,表明INT型最小值 ,这里记录权值和最大 
	LL maxv_d = 0;	//最大的权值和的层数 
    for (int i = 0, length = 1, depth = 1; i < n; depth++, length *= 2)
    {
        LL sum = 0;	//每一层的和 
        for (int j = 0; j < length && i < n; j++, i++ )
        {
            int x;
            cin >> x;
            sum += x;
        }

        if (sum > maxv)
        {
            maxv = sum;
            maxv_d = depth;
        }
    }

    cout << maxv_d << endl;

    return 0;
}

试题H——等差数列

在这里插入图片描述
这道题目考了一点数论知识就是gcd最大公约数,等差数列公式.
由于咱们须要求出最短的等差数列而且包含所给出的数,那么咱们就要求出最大的公差,首先看样例能够推出数列的第一项就是最小的数,数列的末项就是最大的数,咱们只须要求出最大的公约数就能获得最短的长度的等差数列。
咱们将每个数减去第一个数,而后依次找最大公约数,而后经过等差数列的公式便可获得最短的长度。
等差数列公式a[n] - a[1] / d + 1即为求出的等差数列长度。
坑点:
注意若是所给数据相同时,应该返回长度n

#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;
}

由于以前我对每一个数都减掉了a[1]因此最后不用减掉a[1]了。

试题I——后缀表达式

在这里插入图片描述
这道题目是个巨坑啊,不知道怎么说好呢,在用例这里故意卡了个恰好和中缀表达式算出来结果同样的样例来,让人按照中缀表达式来算,所有先排序而后拿大的相加再减掉小的。(本人已入坑)
其实样例中缀表达式来算和后缀表达式来算结果是同样的。
反例:
0 2
1 2 3
咱们若是按照以前想的中缀的话,从大到小排序3 - 2 - 1 = 0
后缀表达式计算 3 -(1 - 2) = 4,其实后缀表达式能够至关于加括号后计算。
其实最大值后缀表达式至关于全部的加号相加,而后再加上剩下的数(除了最小的数之外), 再减掉最小的数。
其实当作一棵树来计算就行。
在这里插入图片描述
减号至关于一个二叉树的根。

#include <bits/stdc++.h>
using namespace std;

typedef long long LL;
const int maxn = 200010;

int n, m;
int a[maxn];

int main()
{
    scanf("%d%d", &n, &m);
    int k = n + m + 1;
    LL sum = 0;
    for (int i = 0; i < k; i++)
    {
        scanf("%d", &a[i]);
        sum += a[i];	//求这些数的和 
    }
    sort(a, a + k);

    if (a[0] >= 0)	//第一个数大于0,说明没有负数,由于以前加过一次a[0],而后咱们原本就须要减掉a[0],因此减掉2*a[0] 
    {
        if (m) sum -= 2 * a[0];
    }
    else		//若是是负数的那么咱们须要加上,由于以前是负数,加上去也就至关于减掉,因此-=2*a[i](a[i]<0) 
    {
        for (int i = 0; i < k && a[i] < 0 && m > 0; i++ )
        {
            sum -= a[i] * 2;
            m-- ;
        }
    }

    cout << sum << endl;
    return 0;
}

试题J——灵能传输

在这里插入图片描述
在这里插入图片描述
其实这道题目代码比较简单,思路比较难想就是思想 + 贪心。这道题目没怎么弄明白,有老师说了这道题目,给出连接,和他的代码:

#include <cstring>
#include <iostream>
#include <algorithm>
#include <limits.h>

using namespace std;

typedef long long LL;
const int N = 300010;

int n;
LL sum[N], a[N], s0, sn;
bool st[N];

int main()
{
    int T;
    scanf("%d", &T);
    while (T -- )
    {
        scanf("%d", &n);
        for (int i = 1; i <= n; i ++ )
        {
            scanf("%lld", &sum[i]);
            sum[i] += sum[i - 1];
        }

        s0 = sum[0], sn = sum[n];
        if (s0 > sn) swap(s0, sn);

        sort(sum, sum + n + 1);

        for (int i = 0; i <= n; i ++ )
            if (s0 == sum[i])
            {
                s0 = i;
                break;
            }
        for (int i = n; i >= 0; i -- )
            if (sn == sum[i])
            {
                sn = i;
                break;
            }

        memset(st, 0, sizeof st);
        int l = 0, r = n;
        for (int i = s0; i >= 0; i -= 2)
        {
            a[l ++ ] = sum[i];
            st[i] = true;
        }
        for (int i = sn; i <= n; i += 2)
        {
            a[r -- ] = sum[i];
            st[i] = true;
        }
        for (int i = 0; i <= n; i ++ )
            if (!st[i])
            {
                a[l ++ ] = sum[i];
            }

        LL res = 0;
        for (int i = 1; i <= n; i ++ ) res = max(res, abs(a[i] - a[i - 1]));
        cout << res << endl;
    }
    return 0;
}

视频讲解:灵能传输