额。。。。提前声明水文章,题目都不难。
文章目录
- 1. 字母数
- 2. 大乘积
- 3. 星期几
- 4.列名
- 5. 最大连通
- 6. 清理水域
- 7. 信号覆盖
- 8. 附近最小
- 9. 第三小
- 10. 3个1
- 11. 装苹果
- 12. 删字母
- 13. 统计次数
- 14. 最小数位和
- 15. 对折次数
- 16. 相近分解
- 17. 电扇控制
- 18. 最尖位置
明天就要比赛了,博主的学校没有蓝桥杯比赛项目,自己瞎学了点,自己在网上找题做,昨天在在蓝桥杯官网上看到一些刷题清单,然后刚发现的时候有点懊悔的样子,早发现的话就能跟着清单刷了,不比一个人盲目的刷好吗?
然后刷着刷着发现不对劲,都挺简单的,直接有自信了好吧!!!
结果刷完第一期的模拟,这题目真就是模拟呗,有点太简单了,基本上都能靠模拟做出来。
省流:8.附近最小(滑动窗口)感觉这道题可能难点。其他的真的挺简单的。
比赛前看看这些模拟题好吧,先给自己的信心满上!!!!
祝各位取得好的成绩😁😁😁。
1. 字母数
题目要求:
求出大于2022中第一个十六进制所有位数全部是字母的数,即每一位全部大于10;
思路:
直接从2023开始模拟就好了,发现第一个满足条件的数,那么就是答案。
答案是2730
#include <bits/stdc++.h>
using namespace std;
bool helpr(int x)
{
while (x)
{
int t = x % 16;
if (t < 10)
return false;
x /= 16;
}
return true;
}
int main()
{
for (int i = 2023; ; i++)
{
if (helpr(i))
{
printf("%d\n", i);
break;
}
}
return 0;
}
2. 大乘积
这道题也是填空题,直接模拟就好了。
答案是189
#include <bits/stdc++.h>
using namespace std;
int main()
{
int a[] = {99, 22, 51, 63, 72, 61, 20, 88, 40, 21, 63, 30, 11, 18, 99, 12, 93, 16, 7, 53, 64, 9, 28, 84, 34, 96, 52, 82, 51, 77};
int sz = sizeof (a) / sizeof (a[0]);
int res = 0;
for (int i = 0; i < sz; i++)
for (int j = i + 1; j < sz; j++)
if (a[i] * a[j] >= 2022)
res++;
printf("%d\n", res);
return 0;
}
3. 星期几
题目要求:
要求我们输入两个数w
和n
分别代表当前是星期几,然后经过了n
天,问经过n
天后是星期几。
思路:
- 我们需要对
n
天除7之后剩下的余数。 - 将余数
r
+原来的天数w
再除7获取余数,就是答案。 - 如果答案是0的话,就证明原本是7.
#include <bits/stdc++.h>
using namespace std;
int w, n;
int main()
{
scanf("%d%d", &w, &n);
int r = n % 7;
int res = (w + r) % 7;
if (res == 0)
printf("%d\n", 7);
else
printf("%d\n", res);
return 0;
}
4.列名
额。。。。。直接用Excel表往后拖就好了。
BYT
5. 最大连通
题目要求:
给一个30*60的全是由0和1构成的矩阵,然后对于1可以能来回的移动,.0则不能移动。问图中最大的连通块是多少。可以理解成1表示陆地,0表示海洋,其中最大的岛多大。
思路:
这道题是经典的图论搜索算法,可以用dfs
和bfs
两种方式解答。
- 遍历所给矩阵,找到未联通的,也是未访问过的。
- 然后对这个点进行
dfs
或者bfs
求出所能涉及到的全部1
.
dfs
void dfs(int x, int y)
{
cur++;
st[x][y] = true;
for (int i = 0; i < 4; i++)
{
int a = x + dx[i], b = y + dy[i];
//未越界, 能访问, 可以到。
if (a >= 0 && a < 30 && b >= 0 && b < 60 && !st[a][b] && g[a][b] == '1')
{
dfs(a, b);
}
}
}
bfs
void bfs(int x, int y)
{
cur++;
st[x][y] = true;
queue<PII> q;
q.push({x, y});
while (q.size())
{
auto t = q.front();
q.pop();
for (int i = 0; i < 4; i++)
{
int a = t.first + dx[i], b = t.second + dy[i];
if (a >= 0 && a < 30 && b >= 0 && b < 60 && !st[a][b] && g[a][b] == '1')
{
cur++;
st[a][b] = true;
q.push({a, b});
}
}
}
}
整体代码:
#include <bits/stdc++.h>
using namespace std;
const int N = 70;
typedef pair<int, int> PII;
char g[N][N];
bool st[N][N];
int res, cur;
int dx[4] = {-1, 0, 1, 0}, dy[4] = {0, 1, 0, -1};
void dfs(int x, int y)
{
cur++;
st[x][y] = true;
for (int i = 0; i < 4; i++)
{
int a = x + dx[i], b = y + dy[i];
//未越界, 能访问, 可以到。
if (a >= 0 && a < 30 && b >= 0 && b < 60 && !st[a][b] && g[a][b] == '1')
{
dfs(a, b);
}
}
}
void bfs(int x, int y)
{
cur++;
st[x][y] = true;
queue<PII> q;
q.push({x, y});
while (q.size())
{
auto t = q.front();
q.pop();
for (int i = 0; i < 4; i++)
{
int a = t.first + dx[i], b = t.second + dy[i];
if (a >= 0 && a < 30 && b >= 0 && b < 60 && !st[a][b] && g[a][b] == '1')
{
cur++;
st[a][b] = true;
q.push({a, b});
}
}
}
}
int main()
{
for (int i = 0; i < 30; i++)
scanf("%s", g[i]);
for (int i = 0; i < 30; i++)
for (int j = 0; j < 60; j++)
{
if (!st[i][j] && g[i][j] == '1')
{
cur = 0;
dfs(i, j);
//bfs(i, j);
res = max(res, cur);
}
}
printf("%d\n", res);
return 0;
}
答案是148
。
6. 清理水域
题目要求:
给定一个n * m
的矩阵全是水草,然后对其进行清理,问说清理完成之后,还有多少没有清理。
思路:
这题暴力模拟就能过:
- 在清理的时候,记录总共清理了多少次,重复清理不必重复计算。
- 最后利用
n * m - sum
就是最后的答案。
#include <bits/stdc++.h>
using namespace std;
const int N = 110;
int n, m, k;
int g[N][N];
int main()
{
scanf("%d%d%d", &n, &m, &k);
int sum = 0;
while (k --)
{
int r1, r2, c1, c2;
scanf("%d%d%d%d", &r1, &c1, &r2, &c2);
for (int i = r1; i <= r2; i++)
for (int j = c1; j <= c2; j++)
{
if (g[i][j] == 0)
sum++;
g[i][j] = 1;
}
}
printf("%d\n", n * m - sum);
return 0;
}
7. 信号覆盖
题目要求:
给一个矩阵,题目中用W
和H
来表示宽和高,也就是矩阵中的行和列。
然后对其进行放置n
次信号塔,信号塔的坐标是r
,问最后能覆盖多少个地方。
思路:
感觉和上一题的dfs很像,只是把dfs换成了检查两点之间的距离。
- 我们遍历矩阵,然后对于每个点判断其是否被覆盖
- 如果没有覆盖,那么去判断其是能能被覆盖。
- 判断覆盖的
check
函数就是两点之间的距离公式。
#include <bits/stdc++.h>
using namespace std;
const int N = 110;
int w, h, n, r;
bool st[N][N];
int res;
bool check(int i, int j, int x, int y)
{
return r * r >= pow(abs(i - x), 2) + pow(abs(j - y), 2);
}
int main()
{
scanf("%d%d%d%d", &w, &h, &n, &r);
while (n --)
{
int x, y;
scanf("%d%d", &x, &y);
for (int i = 0; i < w + 1; i++)
for (int j = 0; j < h + 1; j++)
{
if (!st[i][j] && check(i, j, x, y))
{
res++;
st[i][j] = true;
}
}
}
printf("%d\n", res);
return 0;
}
8. 附近最小
题目要求:
给定一个数组,然后再输入一个k
来表示长度,对于每个i
求出其[i - k, i + k]
这段区间内的最小值。
思路:
典型的滑动窗口题目,但同样这种题目也是能够直接用暴力得到分的题目。
我们会求从[i, k]
的窗口大小,那种题也算是一种模板题, 不懂得可以去Acwing去学习一下,讲的很好的。
- 遍历数组中每一个点,然后用
id
表示当前这个点。 - 构造出窗口大小
l = max(i - k, 0), r = min(i + k, n - 1)
分别取边界的最值,以防止越界。 - 然后判断对头是否不在窗口内,如果不在,将其出队列。
- 紧接着判断当前的id是否小于等于
r
并更新队尾的元素。
#include <bits/stdc++.h>
using namespace std;
const int N = 1e6 + 10;
int n, k;
int a[N];
int que[N], front, rear;
int main()
{
scanf("%d", &n);
for (int i = 0; i < n; i++)
scanf("%d", &a[i]);
scanf("%d", &k);
int id = 0;
for (int i = 0; i < n; i++)
{
//创建窗口
int l = max(i - k, 0), r = min(i + k, n - 1);
//判断对头是否滑出
while (front != rear && que[front] < l) front++;
//将r范围内的数入队列。
while (id <= r)
{
//对队尾进行优化
while (front != rear && a[que[rear - 1]] >= a[id]) rear--;
que[rear++] = id++;
}
printf("%d ", a[que[front]]);
}
return 0;
}
9. 第三小
题目要求:
给我们一个数组,然后从数组第3个位置开始,输出每一个位置上,前面第3小的数。
思路:
- 我们定义一个优先队列(堆)出来,堆中只放3个元素,堆的建立按照大根堆来建立。
- 此时,对于堆顶来说我们就得到第3小的数了。
- 那对于堆的维护来说,如果说当前数组的元素比堆定元素还要小,那么此时的堆顶元素一定是会更新的,因为已经由比其更小的数进来了。
这道题目要注意,相同的数也算。
比如:9 9 8 8 3这个序列,第三小的数是8, 而不是9。
#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 10;
int n;
int a[N];
int main()
{
scanf("%d", &n);
for (int i = 1; i <= n; i++)
scanf("%d", &a[i]);
priority_queue<int, vector<int>, less<int> > heap;
for (int i = 1; i <= 3; i++)
heap.push(a[i]);
for (int i = 4; i <= n; i++)
{
int t = heap.top();
printf("%d ", t);
if (a[i] <= t)
heap.pop(), heap.push(a[i]);
}
printf("%d ", heap.top());
return 0;
}
10. 3个1
题目要求:
求出2进制中正好出现3个1的数,这个数是第23位。
思路:
利用lowbit(x)
函数即可求出每一个数的二进制中1的位数,模板题,如果不会lowbit(x)
可以取Acwing上讲过这个的模板。
答案是70
#include <bits/stdc++.h>
using namespace std;
int lowbit(int x)
{
return x & -x;
}
int main()
{
int res = 0;
for (int i = 7; ; i++)
{
int x = i;
int cnt = 0;
while (x)
{
x -= lowbit(x);
cnt++;
}
if (cnt == 3)
res++;
if (res == 23)
{
printf("%d\n", i);
break;
}
}
return 0;
}
11. 装苹果
签到题。。。
#include <bits/stdc++.h>
using namespace std;
int main()
{
printf("%d\n", 2023 / 36);
return 0;
}
12. 删字母
题目要求:
给定一个字符串,然后对其进行删除m
次删除操作,使其的字典序最小。
思路:
首先这道题可以使用暴力模拟来解决,每次对字符串进行遍历,条件是:只要发现前面的一个大于后面的那一个的时候,就将其删除,这种方式删除后的字典序一定最小。
为了防止字符串原本就是升序,我们可以手动在字符串末尾加0.
#include <bits/stdc++.h>
using namespace std;
int n, m;
string s;
int main()
{
scanf("%d%d", &n, &m);
cin >> s;
s.push_back('0');
while (m--)
{
for (int i = 0; i < s.size() - 1; i++)
{
if (s[i] > s[i + 1])
{
s.erase(i, 1);
break;
}
}
}
s.pop_back();
cout << s << endl;
return 0;
}
单调栈
这道题也可以利用单调增的栈来进行优化。
- 去遍历字符串,如果说栈顶元素大于了当前的元素,那么对其进行出栈。
- 如此循环,栈中就是最后的答案。
- 注意如果说m要是不为0,需要将其栈顶的元素出栈。
但是这道题目的测试用有点弱,加上注释的代码才是正确的,但是不加也能过。
比如我下面这个两个例子:明显输出结果是错误的,却能通过整体的代码。
#include <bits/stdc++.h>
using namespace std;
const int N = 1e6 + 10;
int n, m;
char s[N];
char stk[N];
int top;
int main()
{
scanf("%d%d", &n, &m);
scanf("%s", s);
for (int i = 0; i < n; i++)
{
while (m && top != 0 && stk[top] > s[i])
{
top--;
m--;
}
stk[++top] = s[i];
}
// while (m --)
// top--;
// stk[++top] = '\0';
printf("%s\n", stk + 1);
return 0;
}
13. 统计次数
啊????? 昂?????
题目要求:
统计字符串中1~9
各个出现的次数。
思路:
哈希表。。。。
#include <bits/stdc++.h>
using namespace std;
const int N = 1e4 + 10;
int h[10];
char s[N];
int main()
{
scanf("%s", s);
for (int i = 0; s[i]; i++)
h[s[i] - '0']++;
for (int i = 0; i <= 9; i++)
printf("%d ",h[i]);
return 0;
}
14. 最小数位和
签到题。。只要会求一个数的每一位就好了。
答案是223321
#include <bits/stdc++.h>
using namespace std;
int a[100];
int Get_digit_Sum(int x)
{
int sum = 0;
while (x)
{
sum += x % 10;
x /= 10;
}
return sum;
}
int main()
{
for (int i = 0; i < 64; i++)
scanf("%d", &a[i]);
int sum = Get_digit_Sum(a[0]);
int res = a[0];
for (int i = 1; i < 64; i++)
{
int t = Get_digit_Sum(a[i]);
if (t < sum)
{
sum = t;
res = a[i];
}
}
printf("%d %d\n", res, sum);
return 0;
}
15. 对折次数
啊????还有高手,直接模拟就好了,数据范围大,记得开long long
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
int main()
{
LL l;
scanf("%lld", &l);
LL cnt = 0;
while (l)
{
l /= 2;
cnt++;
}
printf("%lld\n", cnt);
return 0;
}
16. 相近分解
题目要求:
其实题目相当于说,这三个数之间的差不能超过2,然后求第23个数是多少。
思路:
我们可以直接从i = 1
开始模拟,j 和 k 的大小,不能大于 i + 2
就好了。
找到第23个就是答案.
#include <bits/stdc++.h>
using namespace std;
int main()
{
int cnt = 0;
for (int i = 1; ; i++)
for (int j = i; j <= i + 2; j++)
for (int k = j; k <= i + 2; k++)
{
cnt++;
if (cnt == 23)
{
printf("%d\n", i * j * k);
return 0;
}
}
return 0;
}
17. 电扇控制
嗯。。。。。找规律???其实也算不上。
#include <bits/stdc++.h>
using namespace std;
int main()
{
int p;
scanf("%d", &p);
if (p % 3 == 0)
printf("low\n");
else if (p % 3 == 1)
printf("mid\n");
else
printf("high\n");
return 0;
}
// p = 5 -- 1 2 3 4 5
// l m h l m h
//3 % 3 == 0 l
//4 % 3 == 1 m
//5 % 3 == 2 h
18. 最尖位置
差2天比赛了,做题?嗯,你做吧,一做一个不吱声,感觉自己又行了,这模拟题的难度,和真题的难度有亿点大。
#include <bits/stdc++.h>
using namespace std;
const int N = 1e4 + 10;
int n;
int a[N];
int main()
{
scanf("%d", &n);
for (int i = 0; i < n; i++)
scanf("%d", &a[i]);
int res = 0;
for (int i = 1; i < n - 1; i++)
if (a[i] < a[i - 1] && a[i] < a[i + 1])
res = max(res, (a[i - 1] - a[i]) * (a[i + 1] - a[i]) );
printf("%d\n", res);
return 0;
}