第十届蓝桥杯题解

借鉴的博客 戳我

B题

我当时是用手算+excel表格算的,时间很慢,而且不相信自己计算能力,重算了两遍
第十届蓝桥杯题解_第1张图片
== 有一丢丢问题的代码……不能求出52 78 702 类似这种含有Z的字符串==

#include 
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];
        printf("%c\n",str[num % 26]);
        num /= 26;
    }
    for (int i = ans.size() - 1; i >= 0; i--)
    {
        cout << ans[i];
    }
    return 0;
}

D题

这道题目因为分解三个数然后不能重复,还有每个数不包含2,4。
因为这是一个填空题用枚举即可。
我们发现2019 = x + y + z
那么对于一组x,y,z三个数的位置不同也算一种那么,对于x,y,z三个位置相当于有6种摆放位置,我们只需要将枚举结果除以6即可得到答案。
我的想法是对的,可是错了

== 这道题用外部函数调用比较好,我比赛写了太多重复代码orz==

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

EEEEE题嘿!迷宫!

第十届蓝桥杯题解_第2张图片
ps:字典序中D < L < R < U

我做的时候在word把0替换掉找路手动暴力来着……一个小时没成功…word…如果测试数据少一点应该就可以了吧
这道题目看到最短路,最容易想到广度优先搜索,但是这道题目不是要你求最短路长度而是求出最短路的路径,提交一个字符串,最简单的就是将方向数组的每一步上,下,左,右,和D,U,L,R相对应,需要在结构体中添加一个字符串记录即可。方向数组的顺序要按照字典序从小到大的顺序D,L,R,U来跑。

#include 
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 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;
}
/*测试数据如下
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
*/

G题 完全二叉树的权值

第十届蓝桥杯题解_第3张图片
根的深度为·1
第十届蓝桥杯题解_第4张图片
用例: 7 1 6 5 4 3 2 1 —> 2
不知道这道题对没对,忘记了,好像是凑合出来了样例,用了 n来记录循环然后一直乘2啥啥的,但是我不知道完全二叉树不是满二叉树,应该不对
求每一层的和的最大值,至于最大值相同时输出最小的那一层,根本不要考虑,因为你找到最大值以后你就拿后面层数的权值和和最大值比较只要小于就不更新,那么层数也不会更新。这样就可以了,我是边输入,边处理的,因为是二叉树那么我除了第一层输入一个数,然后我们将长度*2,那么长度就为2代表第二层需要输入2个数,然后每次边输入,边处理即可。完全二叉树不是满二叉树,最后一层不一定满。

#include 
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题等差数列

我应该是忽略了问题…… 的关键

因为我们需要求出最短的等差数列并且包含所给出的数,那么我们就要求出最大的公差,首先看样例可以推出数列的第一项就是最小的数,数列的末项就是最大的数,我们只需要求出最大的公约数就能得到最短的长度的等差数列。
我们将每一个数减去第一个数,然后依次找最大公约数,然后通过等差数列的公式即可得到最短的长度。
等差数列公式a[n] - a[1] / d + 1即为求出的等差数列长度。
注意如果所给数据相同时,应该返回长度n
第十届蓝桥杯题解_第5张图片

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

I题 后缀表达式

第十届蓝桥杯题解_第6张图片
嘤嘤嘤,坑!!这道题目是个巨坑啊,不知道怎么说好呢,在用例这里故意卡了个刚好和中缀表达式算出来结果一样的样例来,让人按照中缀表达式来算,全部先排序然后拿大的相加再减掉小的。(本人已入坑)
其实样例中缀表达式来算和后缀表达式来算结果是一样的。
反例:
0 2
1 2 3
我们如果按照之前想的中缀的话,从大到小排序3 - 2 - 1 = 0
后缀表达式计算 3 -(1 - 2) = 4,其实后缀表达式可以相当于加括号后计算。
其实最大值后缀表达式相当于所有的加号相加,然后再加上剩下的数(除了最小的数以外), 再减掉最小的数。

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

你可能感兴趣的:(第十届蓝桥杯题解)