写在前面
Hello大家好我是秋刀鱼,今天给大家带来每日蓝桥杯真题题解。
今天的题目比较简单,但就算遇到简单题也不能松懈,拿下全分才是关键!
往期蓝桥杯真题解析
【十二届蓝桥杯国赛真题】123 — 时间复杂度O(1)的纯数学解法
【蓝桥杯冲刺 day8】题目全解析 —附上LeetCode 每日一题
【蓝桥杯冲刺 day7】 题目全解析 — 附上LeetCode周赛 银联-03. 理财产品
距离和

题目解析
很简单的一道题,题目中说明两个字母间的距离是字母表中的位置,那么只需要让任意两个字符相减就能获得字母间距,枚举每一对字母求得其间距之和,就能够获得答案。
AC代码
#include <iostream>
#include <math.h>
#include <string.h>
using namespace std;
int main()
{
int ans=0;
string str = "LANQIAO";
for(int i=0;i<str.size();++i){
for(int j=i+1;j<str.size();++j){
ans+=abs(str[j]-str[i]);
}
}
cout<<ans;
return 0;
}
扩散
题目解析
一道多源的BFS搜索题目,可以从题目中给定的4个点出发,使用BFS搜索2020次,将搜索到的点做上标记。最终遍历所有可能搜索到的点,求得标记点的数量和即是答案。
虽然说BFS能够解决这道题,但该解法从时间速度与内存消耗角度来看并不是最优解。
这种从某个点开始,向任意方向的扩散问题,均能够转换为求解 曼哈顿距离 解决,这题也不例外。
曼哈顿距离:定义 ( x 1 , y 1 ) , ( x 2 , y 2 ) (x_1,y_1),(x_2,y_2) (x1,y1),(x2,y2),这两点的曼哈顿距离就是 ∣ x 1 − x 2 ∣ + ∣ y 1 − y 2 ∣ |x_1-x_2|+|y_1-y_2| ∣x1−x2∣+∣y1−y2∣ 。
既然最大能够扩散次数为2020,我们只需要搜索所有可能到的的点中,距离任意一个起始点曼哈顿距离 <= 2020的点,就是能够被染成黑色的点。
因此我们就能将这道题转换为求解曼哈顿距离。
那么可能到达点范围使用maxX,maxY,minX,minY圈出,遍历该范围中所有的点即可获得答案。
AC代码
#include <iostream>
#include <math.h>
#define S 2020
using namespace std;
// 获得两个点的曼哈顿距离
int ManHaTonDistance(int x1,int y1,int x2,int y2){
return abs(x1-x2)+abs(y1-y2);
}
int main()
{
int pos[4][2]={{0,0},{2020,11},{11,14},{2000,2000}};
int minX,maxX,minY,maxY;
minX=0;
maxX=2020;
minY=0;
maxY=2000;
// 扩散范围
minX-=S;
minY-=S;
maxY+=S;
maxX+=S;
int ans=0;
for(int x=minX;x<=maxX;++x){
for(int y=minY;y<=maxY;++y){
for(int i=0;i<4;++i){
if(ManHaTonDistance(x,y,pos[i][0],pos[i][1])<=S){
++ans;
break;
}
}
}
}
cout<<ans;
return 0;
}
错误票据

题目解析
可以把这道题当做模拟题来做。
-
定义
set存放出现过的 ID 号 -
定义
map存放断号次数
1、判断是否重复
添加一个数值时,set 中已经存在该数值,即能判断该值重复。
2、判断断号
添加一个数值
v
a
l
val
val 时,如果
v
a
l
+
1
val+1
val+1 没有出现过,那么我就将
v
a
l
+
1
val+1
val+1 在 map 中对应的断号次数加一,对
v
a
l
−
1
val-1
val−1 也执行这样的操作。添加一个数值
v
a
l
val
val 后,因为该数值
v
a
l
val
val 已经出现,所以删去 map 中
v
a
l
val
val 数值的键值对。
最终遍历结束后,map 中存放断号次数为2的值,就是我们要找的断号。
AC代码
// 1:无需package
// 2: 类名必须Main, 不可修改
import java.io.*;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
// 快读类
class cin{
static PrintWriter writer = new PrintWriter(new OutputStreamWriter(System.out));
static BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
static StreamTokenizer in = new StreamTokenizer(reader);
public static int nextInt() throws IOException {
in.nextToken();
return (int) in.nval;
}
public static double nextDouble() throws IOException {
in.nextToken();
return in.nval;
}
public static long nextLong() throws IOException{
in.nextToken();
return (long) in.nval;
}
public static String nextLine() throws IOException{
return reader.readLine();
}
}
public class Main {
static Set<Integer> numberSet = new HashSet<>();
static Map<Integer, Integer> used = new HashMap<>();
public static void add(int val){
if (numberSet.contains(val)) {
return;
}
used.put(val, used.getOrDefault(val, 0) + 1);
}
public static void main(String[] args) throws IOException {
int n = cin.nextInt();
int gapNum = -1;
int doubleNUm = -1;
for (int i = 0; i < n; ++i) {
String[] str = cin.nextLine().split(" ");
for (String s : str) {
int val = Integer.parseInt(s);
if (numberSet.contains(val)) {
doubleNUm = val;
}
numberSet.add(val);
used.remove(val);
int pre = val - 1;
int next = val + 1;
add(pre);
add(next);
}
}
for (Map.Entry<Integer, Integer> entry : used.entrySet()) {
if (entry.getValue() >= 2) {
gapNum = entry.getKey();
break;
}
}
System.out.println(gapNum + " " + doubleNUm);
}
}
倍数问题

解题思路
解题的核心是使用贪心算法。
只需要找到三个数,三个数定义为 a 1 , a 2 , a 3 a_1,a_2,a_3 a1,a2,a3 ,那么一定有 ( a 1 + a 2 + a 3 ) % k = = 0 (a_1+a_2+a_3) \%k ==0 (a1+a2+a3)%k==0。根据取余的性质有: ( ( a 1 % k ) + ( a 2 % k ) + ( a 3 % k ) ) % k = = 0 ((a_1\%k)+(a_2\%k)+(a_3\%k))\%k==0 ((a1%k)+(a2%k)+(a3%k))%k==0 。将待取值 a i a_i ai 按照 a i % k a_i\%k ai%k 的值进行分组,每一组对结果值的影响是相同的。
举个栗子:
现在如果有:0,1 2 3 4 5 6 7 此时
K
=
3
K =3
K=3
那么分组情况为: 0,3,6 分别第0组, 1,4,7 分为第 1组 ,2,5 分为第2 组,组号为取余 K 后的值。
那么为了凑出 K ,现在我需要从这些组中取出数,怎么取呢?还记得 ( ( a 1 % k ) + ( a 2 % k ) + ( a 3 % k ) ) % k = = 0 ((a_1\%k)+(a_2\%k)+(a_3\%k))\%k==0 ((a1%k)+(a2%k)+(a3%k))%k==0 吗?
引入组的概念: ( a 1 组 号 + a 2 组 号 + a 3 组 号 ) % k = = 0 (a_1组号 + a_2 组号 + a_3组号)\%k==0 (a1组号+a2组号+a3组号)%k==0 ,即三个数组号之和取余 K 为 0 ,满足题意。
由此可见定义两个指针 i , j i,j i,j 枚举组的情况,再根据前面的公式,获得第三个组的组号 z z z ,获得的 i , j , z i,j,z i,j,z 分别是 a 1 组 号 , a 2 组 号 , a 3 组 号 a_1组号,a_2组号,a_3组号 a1组号,a2组号,a3组号 。
有了组号后,我们能从该组中取出值,假如
i
=
0
,
j
=
0
,
z
=
0
i=0,j=0,z=0
i=0,j=0,z=0 ,也就是说要取出3个 0 组的值,取出的分别是0,3,6,符合题意。假如
i
=
1
,
j
=
2
,
z
=
0
i=1,j=2,z=0
i=1,j=2,z=0 ,取出 0 组一个值,取出 1 组一个值,取出 2 组 个值,取出的分别是0,1,2,符合题意。
但是不要忘了,如果遍历到的是 i = 2 , j = 2 i=2,j=2 i=2,j=2,计算得 k = 2 k=2 k=2 ,意味着需要取出 2 组3个值,但此时 2 组一共只有两个,无法取出三个,所以不符合题意。
总结一下就是: i , j i,j i,j 都从0开始遍历所有组,根据 ( i + j + z ) % k = = 0 (i + j + z)\%k==0 (i+j+z)%k==0 得到第三组的组号,尝试去组 i,j,z指向的组中取值,如果组中够取那么符合题意,如果组中值个数不足,不符合题意。
但是现在题目中要求的是,取出的值最大,如何处理呢?
题目给出最多取 3 个值,也就是说组中只需要保留 3 个值数据,哪三个值呢?最大的三个值,且每次取值按照值从大到小顺序取出,这样就能保证符合题意的值最大。
AC代码
#include <iostream>
#include <string.h>
#include <climits>
#define M 1001
#define ll long long
using namespace std;
ll arr[M][3];
int main()
{
int n,k;
cin >> n>>k;
for (int i = 0; i < k; ++i) {
for (int j = 0; j < 3; ++j) {
arr[i][j] = INT_MIN;
}
}
while (n--) {
ll val,mod;
cin >> val;
mod = val % k;
// 按照从大到小顺序排
if (arr[mod][0] < val) {
arr[mod][2] = arr[mod][1];
arr[mod][1] = arr[mod][0];
arr[mod][0] = val;
}
else if (arr[mod][1] < val) {
arr[mod][2] = arr[mod][1];
arr[mod][1] = val;
}
else if (arr[mod][0] < val) {
arr[mod][0] = val;
}
}
ll ans = INT_MIN;
for (int i = 0; i < k; ++i) {
for (int j = 0; j < k; ++j) {
int z = k-(i + j + k) % k;
ll val1, val2, val3;
val1 = arr[i][0];
// 取值逻辑
if (i == j && j == z) {
val2 = arr[i][1];
val3 = arr[i][2];
}
else if (i == j) {
val2 = arr[i][1];
val3 = arr[z][0];
}
else if (j == z) {
val2 = arr[j][0];
val3 = arr[j][1];
}
else if (i == z) {
val2 = arr[j][0];
val3 = arr[i][1];
}
else {
val2 = arr[j][0];
val3 = arr[z][0];
}
if (val1 == INT_MIN || val2 == INT_MIN || val3 == INT_MIN) {
continue;
}
ans = max(ans, val1 + val2 + val3);
}
}
cout << ans;
return 0;
}
写在最后
代码、论述中有任何问题,欢迎大家指出,同时如果有任何疑问,也能够在评论区中留言,大家共同讨论共同进步!
如果觉得博主写的不错的话,可以点赞支持一下!
本文详细解析了蓝桥杯编程竞赛中的四道题目,包括计算字符串中字符间距离的总和、多源BFS扩散问题、错误票据的模拟处理及寻找特定条件的三个整数倍数问题。通过AC代码展示了解题思路和解决方案,并提供了相关题目的拓展思考。


4682

被折叠的 条评论
为什么被折叠?



