年号字串
【问题描述】
小明用字母 A 对应数字 1,B 对应 2,以此类推,用 Z 对应 26。
对于 27以上的数字,小明用两位或更长位的字符串来对应,例如 AA 对应 27,AB 对应 28,AZ 对应 52,LQ 对应 329。
请问 2019 对应的字符串是什么?
【解题思路】
2019 % 26 = 77 余 17 ,17 对应 Q
77 % 26 = 2 余 25,25 对应 Y
2 % 26 = 0 余 2, 2 对应 B
若是想直接输出,可在结果后加上64
【代码】
#include <iostream>
using namespace std;
void solve(int n) {
if (!n) {
return ;
}
solve(n / 26);
cout << (char)(n % 26 + 64);
}
int main() {
solve(2019);
return 0;
}
数列求值
【问题描述】
给定数列1, 1, 1, 3, 5, 9, 17, …,从第4 项开始,每项都是前3 项的和。求
第20190324 项的最后4 位数字。
【解题思路】
类似于斐波那契数列的第 n 项,只不过递推式变了,不能用递归,否则爆栈,
还有一个问题是直接算到第 20190324 项肯定是会溢出的,在计算过程中要进行取余操作。
【代码】
#include<bits\stdc++.h>
using namespace std;
int solve(int n) {
if (n <= 3) {
return 1;
}
int a = 1, b = 1, c = 1, res;
for (int i = 4; i <= n; i++) {
//递归的时候取余
res = (a + b + c) % 10000;
a = b;
b = c;
c = res;
}
return res;
}
int main() {
cout << solve(20190324) << endl;
return 0;
}
数的分解
【问题描述】
把2019分解成3个各不相同的正整数之和,并且要求每个正整数都不包含数字2和4,一共有多少种不同的分解方法?
注意交换3个整数的顺序被视为同一种方法,例如1000+1001+18 和1001+1000+18 被视为同一种。
【思路分析】
这题麻烦的地方是重复的情况,针对此问题有以下两种情况解决【建议收藏】
1.全部计算完后再除去重复
如以a开头的情况有,bc,cb两种情况,那么一组数a,b,c就会有6种情况
我们只要得出结果后/6即可。
2.循环的时候控制a,b,c的起始值
即 a 从 1 开始, b 从 a + 1 开始,c 从 b + 1 开始。这样 a, b 和 c 就不会相等,同时也不会出现重复,
因为每一次循环得到的 a, b 和 c 和之前出现过的 a, b 和 c 中必定至少有一个数不同,这样得到的结果就是最终结果。
这两种方法代码运行都会超时。
#include<iostream>
using namespace std;
bool judge(int n) {
int t;
while(n) {
if (((t = n % 10) == 2) || t == 4) {
return true;
}
n /= 10;
}
return false;
}
bool check(int a, int b, int c) {
//把判断2,4的代码写成一个函数
//还要把重复的数排除
if (judge(a) || judge(b) || judge(c) || a == b || a == c || b == c) {
return false;
}
return true;
}
int main() {
int res = 0;
for (int i = 1; i < 2018; i++) {
for (int j = 1; j < 2018; j++) {
for (int k = 1; k < 2018; k++) {
if (i + j + k == 2019) {
res += check(i, j, k);
//这里的check函数时bol类型的,最后返回值不是1就是0
}
}
}
}
cout << res / 6 << endl;
return 0;
}
/**
* 第二种思路:循环的时候控制变量的起始值:
*/
int main() {
int res = 0;
for (int i = 1; i < 2018; i++) {
for (int j = i + 1; j < 2018; j++) {
for (int k = j + 1; k < 2018; k++) {
if (i + j + k == 2019) {
res += check(i, j, k);
}
}
}
}
cout << res << endl;
return 0;
}
迷宫
【问题描述】
下图给出了一个迷宫的平面图,其中标记为1 的为障碍,标记为0 的为可
以通行的地方。
010000
000100
001001
110000
迷宫的入口为左上角,出口为右下角,在迷宫中,只能从一个位置走到这
个它的上、下、左、右四个方向之一。
对于上面的迷宫,从入口开始,可以按DRRURRDDDR 的顺序通过迷宫,
一共10 步。其中D、U、L、R 分别表示向下、向上、向左、向右走。
对于下面这个更复杂的迷宫(30 行50 列),请找出一种通过迷宫的方式,
其使用的步数最少,在步数最少的前提下,请找出字典序最小的一个作为答案。
请注意在字典序中D<L<R<U。
【思路分析】
这题首先要考虑是用dfs还是bfs,关于dfs和bfs的区别可以看这个博客
这题是要得到最优解,所以此题解用bfs算法。
接下来是在写代码过程中一些注意的点,我将会在代码中用数字①…标记
蓝桥杯初赛中dfs和bfs考得比较多,大家可以找2到经典题(没有改编的),把模板弄清楚
再把历届试题里的这类题放在一起分析出题者在这类题上的可能出题点。
#include <iostream>
#include<string>
#include<queue>
using namespace std;
const int N = 30, M = 50;
char map[N][M];
//①这里要按字典顺序
int dir[4][2] = { {1,0},{0,-1},{0,1},{-1,0} };//D<L<R<U
char ch[4] = { 'D','L','R','U' };
int vis[N][M] = { 0 };
struct point {
int x, y;
string rode;
point(int a, int b) {
x = a;
y = b;
}
};
void bfs() {
queue<point>q;
point p(0, 0);//第一个点
q.push(p);//存入队列
vis[0][0] = 1;
while (!q.empty()) {
point t = q.front();//取出第一个点
q.pop();
if (t.x == N - 1 && y == M - 1) {
cout << t.rode << endl;
break;
}
//遍历4个方向
for (int i = 0; i < 4; i++) {
int dx = t.x + dir[i][0];
int dy = t.y + dir[i][1];
//只判断下个方向的坐标,如果合适,就存入这个点下的路径
//还有题目中要求的最优路径也达到了,因为是按着字典顺序,
//所以第一次的结果就是最优解
if (dx >= 0 && dx < N && dy >= 0 && dy < M) {
if (map[dx][dy] == '0' && !vis[dx][dy]) {
point tt(dx, dy);//建立一个新的点
tt.rode = t.rode + ch[i];//存储路径
q.push(tt);
vis[dx][dy] = 1;
//这里就没有回溯了,如果得到结果,那么就是最优解
}
}
}
}
}
int main()
{
for (int i = 0; i < N; i++)
{
for (int j = 0; j < M; j++)
scanf("%c", &map[i][j]);
getchar();//读掉回车
}
bfs();
return 0;
}
完全二叉树的权值
【问题描述】
给定一棵包含N 个节点的完全二叉树,树上每个节点都有一个权值,按从
上到下、从左到右的顺序依次是A1, A2, AN,如下图所示:
现在小明要把相同深度的节点的权值加在一起,他想知道哪个深度的节点
权值之和最大?如果有多个深度的权值和同为最大,请你输出其中最小的深度。
注:根的深度是1。
【思路分析】:这题还算简单的,即使没有二叉树的知识也可以做出来。如图可以知道,每一层的结点数为i*2^(n-1)即,1,2,4,8…
#include<bits\stdc++.h>
using namespace std;
vector<int>a;
int p(int x) {//x为层数,此函数计算每一层的最大节点下标
int t = 1;
while (x--) t *= 2;
return t;
}
int main() {
int n, i = 2;//这里I=2是因为第一个点为单电
int j = 2;//j表示层数,从第二层开始
cin >> n;
int t = 1;//t为要输出的层数,最开始为1
for (int h = 1; h <= n; h++)cin >> a[h];
long long maxx = a[1];//先把第一个点作为最大值
while (i <= n) {//
long long k = 0;//临时最大值
for (; i < p(j) && i <= n; i++) {
k += a[i];//把这一层所有的节点加起来
}
if (k > maxx) maxx = k, t = j;
j++;
}
cout << t << endl;
return 0;
}
等差数列
【题目描述】数学老师给小明出了一道等差数列求和的题目。但是粗心的小明忘记了一
部分的数列,只记得其中 N 个整数。
现在给出这 N 个整数,小明想知道包含这 N 个整数的最短的等差数列有
几项?
【输入格式】
输入的第一行包含一个整数 N。
第二行包含 N 个整数 A 1 ,A 2 ,··· ,A N 。(注意 A 1 ∼ A N 并不一定是按等差数
列中的顺序给出)
【输出格式】
输出一个整数表示答案。
【样例输入】
5
2 6 4 10 20
【样例输出】
10
【样例说明】
包含 2、6、4、10、20 的最短的等差数列是 2、4、6、8、10、12、14、16、
18、20。
【思路分析】思路就是求出给出的数字中最小公差,然后用数字中的最大数字 - 最小数字除以 2 再加 1 就行了,注意公差为 0 的时候的处理。注意排序
#include <iostream>
#include <algorithm>
#include <cmath>
using namespace std;
int value[100010];
int gcd(int a, int b) {
int t;
while (a) {
t = a;
a = b % a;
b = t;
}
return b;
}
int main() {
int n, d, t;
int maxx = 0, minn = 0x7fffffff;
cin >> n;
for (int i = 0; i < n; i++) {
scanf("%d", value + i);
maxx = max(maxx, value[i]);
minn = min(minn, value[i]);
}
sort(value, value + n);
// 求出所有相邻数字差值的最大公约数
d = value[1] - value[0];
for (int i = 2; i < n; i++) {
d = gcd(d, value[i] - value[i-1]);
}
// 注意公差为 0 的处理
if (d == 0) {
cout << n << endl;
} else {
cout << ((maxx - minn) / d + 1) << endl;
}
return 0;
}