蓝桥杯31天真题冲刺|题解报告|第二十六天
Posted Snippet~
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了蓝桥杯31天真题冲刺|题解报告|第二十六天相关的知识,希望对你有一定的参考价值。
大家好,我是snippet,今天是刷蓝桥真题的第二十六天,今天的知识点包含搜索+动态规划,下面是我今天的题解
目录
题目链接:B-玩具_牛客小白月赛69 (nowcoder.com)
题目链接:滑雪_牛客题霸_牛客网 (nowcoder.com)
题目链接:abb_牛客题霸_牛客网 (nowcoder.com)
题目链接:小红取数_牛客题霸_牛客网 (nowcoder.com)
一、玩具
题目链接:B-玩具_牛客小白月赛69 (nowcoder.com)
题目内容:
题目描述:
有 n 个玩具,第 i 个玩具的价格是 ai 元,超市里搞促销活动,购买 2 个玩具即可免单其中价格较低的一个,价格相等也免单其中一个。牛牛想买下所有玩具,至少需要花多少元?
输入描述:
第一行一个正整数 n(1≤n≤10^6)。
第二行 n 个正整数,第 i 个表示 ai(1≤ai≤10^9)。
输出描述:
输出一行一个正整数,表示答案。
示例1
输入
3
1 2 3
输出
4
说明
第二个和第三个一起买,花 3 元,再花 1 元买下第一个,合计 4 元。
时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 262144K,其他语言524288K
64bit IO Format: %lld
解题思路:
因为买玩具可以买一送一嘛,买贵的送便宜的 那我们就先从所有玩具中找到最贵的,买它 然后送只比它便宜的另外一个玩具 重复进行这个操作,就可以用最少的钱买这所有的玩具了
代码:
package 蓝桥杯31天真题冲刺.Day26;
import java.io.*;
import java.util.Arrays;
/**
* @author snippet
* @data 2023-03-29
* 玩具-牛客网
*/
public class T1_玩具
static BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
static PrintWriter pw = new PrintWriter(new BufferedWriter(new OutputStreamWriter(System.out)));
static int n;
static long sum;
static int N = 1000010;
static long[] arr = new long[N];
public static void main(String[] args) throws IOException
String[] s = br.readLine().split(" ");
n = Integer.parseInt(s[0]);
s = br.readLine().split(" ");
for (int i = 0; i < n; i++)
arr[i] = Long.parseLong(s[i]);
Arrays.sort(arr, 0, n);
for (int i = n-1; i >= 0; i-=2)
sum += arr[i];
pw.println(sum);
pw.flush();
br.close();
二、滑雪
题目链接:滑雪_牛客题霸_牛客网 (nowcoder.com)
题目内容:
题目描述:
给定一个 n×m 的矩阵,矩阵中的数字表示滑雪场各个区域的高度,你可以选择从任意一个区域出发,并滑向任意一个周边的高度严格更低的区域(周边的定义是上下左右相邻的区域)。请问整个滑雪场中最长的滑道有多长?(滑道的定义是从一个点出发的一条高度递减的路线)。
(本题和矩阵最长递增路径类似,该题是当年NOIP的一道经典题)
数据范围: 1≤n,m≤100 ,矩阵中的数字满足 1≤val≤1000输入描述:
第一行输入两个正整数 n 和 m 表示矩阵的长宽。
后续 n 行输入中每行有 m 个正整数,表示矩阵的各个元素大小。输出描述:
输出最长递减路线。
示例1
输入:
5 5
1 2 3 4 5
16 17 18 19 6
15 24 25 20 7
14 23 22 21 8
13 12 11 10 9
输出:
25
说明:
从25出发,每次滑向周边比当前小 1 的区域。 25->24->23->22->......->1
解题思路:
找到最长的递减的滑雪路径,我们可以使用dfs来对每个位置进行记忆化遍历搜索,如果它周围有高度比它低的区域,就对满足条件的区域进行递归遍历,每一条路递归遍历之后记得要回溯
代码:
package 蓝桥杯31天真题冲刺.Day26;
import java.io.*;
/**
* @author snippet
* @data 2023-03-29
* DP18_滑雪-牛客网
*/
// 记忆化搜索
public class T2_DP18_滑雪
static BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
static PrintWriter pw = new PrintWriter(new BufferedWriter(new OutputStreamWriter(System.out)));
static int n,m,ans;
static int N = 101;
static int[][] arr = new int[N][N];
static boolean[][] visit = new boolean[N][N];
static int[] dx = 0, 0, 1, -1;
static int[] dy = 1, -1, 0, 0;
// 记忆化搜索
static void dfs(int x, int y, int cnt)
// 每次遍历一个位置的时候都进行一次答案更新
ans = Math.max(ans, cnt);
// 标记遍历的位置
visit[x][y] = true;
for (int i = 0; i < 4; i++)
int x1 = x + dx[i];
int y1 = y + dy[i];
if (x1 > 0 && x1 <= n && y1 > 0 && y1 <= m && arr[x][y] > arr[x1][y1] && !visit[x1][y1])
// 递归
dfs(x1, y1, cnt+1);
// 回溯
visit[x][y] = false;
public static void main(String[] args) throws IOException
String[] s = br.readLine().split(" ");
n = Integer.parseInt(s[0]);
m = Integer.parseInt(s[1]);
for (int i = 1; i <= n; i++)
s = br.readLine().split(" ");
for (int j = 1; j <= m; j++)
arr[i][j] = Integer.parseInt(s[j-1]);
for (int i = 1; i <= n; i++)
for (int j = 1; j <= m; j++)
dfs(i, j, 1);
pw.println(ans);
pw.flush();
br.close();
三、abb
题目链接:abb_牛客题霸_牛客网 (nowcoder.com)
题目内容:
题目描述
leafee 最近爱上了 abb 型语句,比如“叠词词”、“恶心心”
leafee 拿到了一个只含有小写字母的字符串,她想知道有多少个 "abb" 型的子序列?
定义: abb 型字符串满足以下条件:1.字符串长度为 3 。
2.字符串后两位相同。
3.字符串前两位不同。
输入描述:
第一行一个正整数 n
第二行一个长度为 n 的字符串(只包含小写字母)
1≤n≤10^5
输出描述:
"abb" 型的子序列个数。
示例1
输入:
6
abcbcc
输出:
8
说明:
共有1个abb,3个acc,4个bcc
示例2
输入:
4
abbb
输出:
3
解题思路:
因为是求给定的字符串中只根据前后顺序来排子串,满足abb型的子串的个数(如果a,b,b字符一样,但是在字符串中的位置不一样,按不同种进行计算)
我最开始想到的是直接三层for循环进行遍历,因为数据范围是1≤n≤10^5,肯定会超时,没想到居然过了72.73%
根据题意,我们可以使用后缀和来求解,因为是求abb的串的个数,那我们就可以先给定a,然后求a后面的b的个数,那我们可以求每个位置数的后面字符的每个字符(a-z)的字符数和,然后我们对每个数进行遍历,再根据它的后缀和中每个字符的个数k来进行答案求和, ans += ki * (ki-1) / 2 (i=> [a, z]);(ka表示这个字符包括自己 后面的字符中含有a的个数)
代码:
package 蓝桥杯31天真题冲刺.Day26;
import java.io.*;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.Map;
/**
* @author snippet
* @data 2023-03-29
* abb-牛客网
*/
public class T3_abb
static BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
static PrintWriter pw = new PrintWriter(new BufferedWriter(new OutputStreamWriter(System.out)));
static int n;
static long ans;
static int N = 100010;
static char[] c;
static int[][] h = new int[N][26];// 二维数组h表示每个i后面的所有字母a-b的个数
public static void main(String[] args) throws IOException
String[] s = br.readLine().split(" ");
n = Integer.parseInt(s[0]);
s = br.readLine().split(" ");
c = s[0].toCharArray();
int len = c.length;
// 求后缀和
// 列表示每个字母 行0-26表示这个字母以及后面的字母a-z的数的个数 存的数表示
for (int i = len-1; i >= 0; i--)
char a = c[i];
for (int j = 0; j < 26; j++)
h[i][j] = h[i+1][j];
// 把自己加上
h[i][a-'a']++;
for (int i = 0; i < len; i++)
char a = c[i];
for (int j = 0; j < 26; j++)
if (a - 'a' != j)
ans += (long) h[i][j] * (h[i][j]-1) / 2;
pw.println(ans);
pw.flush();
br.close();
// // for循环 暴力求解 案例通过率:72.73%
// static BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
// static PrintWriter pw = new PrintWriter(new BufferedWriter(new OutputStreamWriter(System.out)));
//
// static int n,ans;
// static char[] c;
//
// public static void main(String[] args) throws IOException
// String[] s = br.readLine().split(" ");
// n = Integer.parseInt(s[0]);
// s = br.readLine().split(" ");
// c = s[0].toCharArray();
// int len = c.length;
// for (int i = 0; i < len; i++)
// char a = c[i];
// for (int j = i+1; j < len; j++)
// char b = c[j];
// if (a != b)
// for (int k = j+1; k < len; k++)
// char d = c[k];
// if (a != b && b == d) ans++;
//
//
//
//
//
// pw.println(ans);
// pw.flush();
// br.close();
//
四、小红取数
题目链接:小红取数_牛客题霸_牛客网 (nowcoder.com)
题目内容:
题目描述:
小红拿到了一个数组,她想取一些数使得取的数之和尽可能大,但要求这个和必须是 k 的倍数。
你能帮帮她吗?输入描述:
第一行输入两个正整数 n 和 k
第二行输入 n 个正整数 ai
1≤n,k≤10^3
1≤ai≤10^10
输出描述:
如果没有合法方案,输出 -1。
否则输出最大的和。示例1
输入:
5 5
4 8 2 9 1
复制输出:
20
说明:
取后四个数即可
解题思路:
因为我们要求给定的n个数中,任意取1至n个相加,组成的数x满足x%k == 0,求x的最大值,
那我们就可以使用二维dp对i个数中对k取余得到的每种情况进行状态转移,二维数组f[i][j]表示 每个数i与前面i个数中对k取模的值为j的最大值,f[n][0]也就是我们要求的最大的和
状态转移式:f[i][(j+arr[i])%k] = max(f[i-1][j] + arr[i], f[i-1][(j+arr[i])%k]);
代码:
package 蓝桥杯31天真题冲刺.Day26;
import java.io.*;
import java.util.Arrays;
/**
* @author snippet
* @data 2023-03-29
* 小红取数-牛客网
*/
// 动态规划 二维dp
public class T4_DP40_小红取数
static BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
static PrintWriter pw = new PrintWriter(new BufferedWriter(new OutputStreamWriter(System.out)));
static int n,k;
static int N = 1010;
static long[] arr = new long[N];
static long[][] f = new long[N][N];// 二维数组f 行i表示前i个数 列表示这前i个数中%k的余数为j的最大值
public static void main(String[] args) throws IOException
String[] s = br.readLine().split(" ");
n = Integer.parseInt(s[0]);
k = Integer.parseInt(s[1]);
s = br.readLine().split(" ");
for (int i = 1; i <= n; i++)
arr[i] = Long.parseLong(s[i-1]);
// 数据初始化
for (int i = 0; i <= n; i++)
Arrays.fill(f[i], Long.MIN_VALUE);
// 状态初始化 0个数
f[0][0] = 0;
for (int i = 1; i <= n; i++)
for (int j = 0; j < k; j++)
// 状态转移
f[i][(int) ((j+arr[i])%k)] = Math.max(f[i-1][j]+arr[i], f[i-1][(int) ((j+arr[i])%k)]);
// 如果没有合法方案就输出-1
pw.println(f[n][0] > 0 ? f[n][0] : -1);
pw.flush();
br.close();
蓝桥杯31天真题冲刺|题解报告|第二十一天
大家好,我是snippet,今天是刷蓝桥真题的第二十一天,今天有些事情,还有几个题没看,明天补题
目录
一、灭鼠先锋
题目内容:
问题描述
本题为填空题,只需要算出结果后,在代码中使用输出语句将所填结果输出即可。
灭鼠先锋是一个老少咸宜的棋盘小游戏,由两人参与,轮流操作。
灭鼠先锋的棋盘有各种规格,本题中游戏在两行四列的棋盘上进行。游戏的规则为:两人轮流操作,每次可选择在棋盘的一个空位上放置一个棋子,或在同一行的连续两个空位上各放置一个棋子,放下棋子后使棋盘放满的一方输掉游戏。
小蓝和小乔一起玩游戏,小蓝先手,小乔后手。小蓝可以放置棋子的方法很多,通过旋转和翻转可以对应如下四种情况:
XOOO XXOO OXOO OXXO
OOOO OOOO OOOO OOOO其中 O 表示棋盘上的一个方格为空,X 表示该方格已经放置了棋子。
请问,对于以上四种情况,如果小蓝和小乔都是按照对自己最优的策略来玩游戏,小蓝是否能获胜。如果获胜,请用 V 表示,否则用 L 表示。请将四种情况的胜负结果按顺序连接在一起提交。
运行限制
- 最大运行时间:1s
- 最大运行内存: 256M
解题思路:
手撸下棋情况
代码:
package 蓝桥杯31天真题冲刺.Day21;
/**
* @author snippet
* @data 2023-03-24
* 灭鼠先锋
*/
public class T1_灭鼠先锋
public static void main(String[] args)
System.out.println("LLLV");
二、小蓝与钥匙
题目链接:小蓝与钥匙 - 蓝桥云课 (lanqiao.cn)
题目内容:
问题描述
小蓝是幼儿园的老师, 他的班上有 28 个孩子, 今天他和孩子们一起进行了 一个游戏。
小蓝所在的学校是寄宿制学校, 28 个孩子分别有一个自己的房间, 每个房 间对应一把钥匙, 每把钥匙只能打开自己的门。现在小蓝让这 28 个孩子分别将 自己宿舍的钥匙上交, 再把这 28 把钥匙随机打乱分给每个孩子一把钥匙, 有 28!=28×27×⋯×128!=28×27×⋯×1 种分配方案。小蓝想知道这些方案中, 有多少种方案恰有 一半的孩子被分到自己房间的钥匙 (即有 14 个孩子分到的是自己房间的钥匙, 有 14 个孩子分到的不是自己房间的钥匙)。
答案提交
这是一道结果填空的题,你只需要算出结果后提交即可。本题的结果为一 个整数, 在提交答案时只填写这个整数, 填写多余的内容将无法得分。
运行限制
- 最大运行时间:1s
- 最大运行内存: 512M
解题思路:
代码:
三、李白打酒加强版
题目链接:李白打酒加强版 - 蓝桥云课 (lanqiao.cn)
四、机房
以上是关于蓝桥杯31天真题冲刺|题解报告|第二十六天的主要内容,如果未能解决你的问题,请参考以下文章