【春招笔试】2025.05.10美团春招笔试真题改编题
✅ 春招备战指南 ✅
💡 学习建议:
- 先尝试独立解题(建议用时:90分钟/套)
- 对照解析查漏补缺
🧸 题面描述背景等均已深度改编,做法和题目本质基本保持一致。
🍹 感谢各位朋友们的订阅,你们的支持是我们创作的最大动力
🌸 目前本专栏已经上线60+套真题改编解析,后续会持续更新的
春秋招合集 -> 互联网必备刷题宝典🔗
题目一:星际旅行计划
1️⃣:统计数组中值为1的元素数量
2️⃣:计算曼哈顿距离并判断奇偶性关系
难度:中等
这道题目的关键在于理解移动的特性,值为0的元素让我们原地不动,值为1的元素允许在四个方向上移动一步。通过数学分析,我们可以推导出一个O(n)的高效解法,无需模拟实际移动过程。
题目二:山脉平滑优化
1️⃣:计算初始陡峭度和差分数组
2️⃣:分析区间操作对边界点的影响
3️⃣:使用后缀最小值优化求解最优操作区间
难度:中等
这道题目需要理解区间加一操作如何影响整体陡峭度。通过分析,我们发现只有区间边界处的差值会发生变化,从而可以快速计算每个可能区间的影响,得到最优解。
题目三:双递增子序列划分问题
1️⃣:利用Dilworth定理将问题转化为不存在长度为3的不增子序列
2️⃣:预处理每个位置的左右不增边界
3️⃣:使用扫描线算法和树状数组高效处理多次查询
难度:中等偏难
这道题目结合了经典的序列分解理论和高效的数据结构。通过理论分析,将问题转化为判断是否存在特定模式,然后设计离线算法高效处理多次查询,时间复杂度为O((n+q)logn)。
01. 星际旅行计划
问题描述
小柯是一名星际探险家,她正在一个无限广阔的二维宇宙中规划航行路线。初始时,她的飞船位于坐标 。
她的飞船能量系统由 个能量单元组成,每个能量单元的值为
。当小柯使用第
个能量单元时,她必须选择两个整数
和
,满足
,然后飞船会移动到新的位置
。
小柯想知道,在使用完所有 个能量单元后,她是否能恰好到达目标坐标
?
输入格式
第一行包含一个整数 ,表示测试用例的数量。
对于每个测试用例:
- 第一行包含一个整数
,表示能量单元的数量。
- 第二行包含
个整数,第
个整数为
,表示每个能量单元的值。
- 第三行包含四个整数
,分别表示起始坐标和目标坐标。
数据保证单个测试文件中 。
输出格式
对于每个测试用例输出一行,如果小柯能够恰好到达目标坐标 ,则输出 "YES",否则输出 "NO"。
样例输入
2
2
0 0
1 1 1 1
3
1 1 1
1 1 2 2
样例输出
YES
NO
样例1 | 在这个例子中,小柯有两个值为0的能量单元。使用第一个能量单元,她可以选择 |
样例2 | 小柯有三个值为1的能量单元。无论如何选择,她无法从 |
数据范围
- 所有测试用例中
的总和不超过
题解
这道题目看似复杂,但实际上有一个很直观的解法。让我们分析一下:
首先,我们需要理解能量单元的使用方式。当 时,我们只能选择
和
,即原地不动。当
时,我们有四种选择:
、
、
或
,相当于在四个方向上移动一步。
所以,我们的移动能力受到两个因素限制:
- 总共能移动多少步(由
的数量决定)
- 每一步只能在四个正交方向上移动
从起点 到目标点
的最短曼哈顿距离是
。这意味着我们至少需要这么多步才能到达目标。
此外,每次移动都会改变奇偶性。考虑到这一点,能否到达目标还需满足一个条件:如果总移动步数减去最短距离后的剩余步数是奇数,那么我们永远无法到达目标。因为每多走两步才能回到同一个奇偶性的位置。
综合这两个条件,我们可以得出解题的关键判断:
- 设
为数组中值为1的元素数量(即可移动的步数)
- 设
,
为横纵坐标的距离
- 当且仅当
且
时,才能到达目标
时间复杂度:,我们只需要遍历一次数组来统计值为1的元素数量。 空间复杂度:
,只需要常数额外空间。
参考代码
- Python
import sys
input = lambda:sys.stdin.readline().strip()
def solve():
t = int(input())
for _ in range(t):
n = int(input())
a = list(map(int, input().split()))
x, y, p, q = map(int, input().split())
# 统计可移动的步数
ones = sum(1 for val in a if val == 1)
# 计算目标距离
dx = abs(p - x)
dy = abs(q - y)
# 判断是否可达
if ones >= dx + dy and (ones - (dx + dy)) % 2 == 0:
print("YES")
else:
print("NO")
if __name__ == "__main__":
solve()
- Cpp
#include <iostream>
#include <cmath>
using namespace std;
using ll = long long;
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int t;
cin >> t;
while (t--) {
int n;
cin >> n;
ll ones = 0;
for (int i = 0; i < n; i++) {
int a;
cin >> a;
ones += (a == 1);
}
ll x, y, p, q;
cin >> x >> y >> p >> q;
ll dx = abs(p - x);
ll dy = abs(q - y);
if (ones >= dx + dy && (ones - (dx + dy)) % 2 == 0)
cout << "YES\n";
else
cout << "NO\n";
}
return 0;
}
- Java
import java.io.*;
import java.util.*;
public class Main {
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
int t = Integer.parseInt(br.readLine().trim());
while (t-- > 0) {
int n = Integer.parseInt(br.readLine().trim());
String[] vals = br.readLine().trim().split(" ");
long ones = 0;
for (int i = 0; i < n; i++) {
if (vals[i].equals("1")) ones++;
}
String[] coords = br.readLine().trim().split(" ");
long x = Long.parseLong(coords[0]);
long y = Long.parseLong(coords[1]);
long p = Long.parseLong(coords[2]);
long q = Long.parseLong(coords[3]);
long dx = Math.abs(p - x);
long dy = Math.abs(q - y);
if (ones >= dx + dy && (ones - (dx + dy)) % 2 == 0)
System.out.println("YES");
else
System.out.println("NO");
}
}
}
02. 山脉平滑优化
问题描述
小基 是一位地质学家,她正在研究一座山脉的高度数据。她定义了一个"陡峭度"的概念:相邻两个测量点高度之差的绝对值之和。
现在,小基 准备使用一种特殊的地形修整技术,可以最多对山脉的一个连续区段进行一次操作:选择一个区间,使得该区间内所有高度值增加 米。
小基 希望操作后山脉的陡峭度尽可能小,你能帮她找出最优的操作方案吗?
输入格式
第一行包含一个正整数 ,表示测试用例的数量。
对于每个测试用例:
- 第一行包含一个正整数
,表示山脉测量点的数量。
- 第二行包含
个正整数
,表示每个测量点的高度。
保证所有测试用例中 的总和不超过
。
输出格式
对于每个测试用例输出一行,包含一个整数,表示最小可能的陡峭度。
样例输入
2
5
1 4 2 3 4
3
1 2 1
样例输出
5
1
样例1 | 选择 |
样例2 | 选择 |
数据范围
- 所有测试用例中
的总和不超过
题解
这道题目的关键在于理解区间加一操作对整体陡峭度的影响。
首先,我们定义陡峭度 为相邻元素差的绝对值之和:
当我们对区间 内的所有元素加
时,只有区间的两个边界处的差值会发生变化:
- 左边界:
增加
,影响
的值(如果
)
- 右边界:
增加
,影响
的值(如果
)
为了方便计算这种影响,我们可以定义一个数组 ,其中
,表示第
和第
个元素的差值。 初始陡峭度就是
。
当我们对区间 进行操作时:
- 左边界变化:
(如果
)
- 右边界变化:
(如果
)
总的变化量为 。我们需要找到使
最小的区间,最终陡峭度为
。
使用后缀最小值优化,我们可以高效地求出每个可能的左边界 对应的最佳右边界
,从而找到全局最优解。
时间复杂度:,我们只需要遍历一次数组计算初始陡峭度,然后再遍历一次找出最优区间。 空间复杂度:
,需要存储差值数组和后缀最小值数组。
参考代码
- Python
import sys
input = lambda:sys.stdin.readline().strip()
def solve():
t = int(input())
for _ in range(t):
n = int(input())
a = list(map(int, input().split()))
# 计算初始陡峭度
diff = [a[i+1] - a[i] for i in range(n-1)]
s0 = sum(abs(d) for d in diff)
# 计算左边界影响
f = [0] * n
for l in range(1, n):
f[l] = abs(diff[l-1] + 1) - abs(diff[l-1])
# 计算右边界影响
g = [0] * n
for r in range(n-1):
g[r] = abs(diff[r] - 1) - abs(diff[r])
g[n-1] = 0
# 计算后缀最小值
min_g = [0] * n
min_g[n-1] = g[n-1]
for i in range(n-2, -1, -1):
min_g[i] = min(g[i], min_g[i+1])
# 寻找最优区间
min_delta = float('inf')
for l in range(n):
min_delta = min(min_delta, f[l] + min_g[l])
print(s0 + min_delta)
if __name__ == "__main__":
solve()
- Cpp
#include <iostream>
#include <vector>
#include <climits>
#include <cmath>
using namespace std;
using ll = long long;
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int t;
cin >> t;
while (t--) {
int n;
cin >> n;
vector<ll> a(n);
for (int i = 0; i < n; ++i) {
cin >> a[i];
}
// 计算初始陡峭度
vector<ll> diff(n-1);
ll s0 = 0;
for (int i = 0; i < n-1; ++i) {
diff[i] = a[i+1] - a[i];
s0 += abs(diff[i]);
}
// 计算边界影响
vector<ll> f(n), g(n);
f[0] = 0;
for (int l = 1; l < n; ++l) {
f[l] = abs(diff[l-1] + 1) - abs(diff[l-1]);
}
g[n-1] = 0;
for (int r = 0; r < n-1; ++r) {
g[r] = abs(diff[r] - 1) - abs(diff[r]);
}
// 计算后缀最小值
vector<ll> min_g(n);
min_g[n-1] = g[n-1];
for (int i = n-2; i >= 0; --i) {
min_g[i] = min(g[i], min_g[i+1]);
}
// 寻找最优解
ll min_d = LLONG_MAX;
for (int l = 0; l < n; ++l) {
min_d = min(min_d, f[l] + min_g[l]);
}
cout << s0 + min_d << "\n";
}
return 0;
}
- Java
import java.io.*;
import java.util.*;
public class Main {
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
int t = Integer.parseInt(br.readLine().trim());
w
剩余60%内容,订阅专栏后可继续查看/也可单篇购买
互联网刷题笔试宝典,这里涵盖了市面上大部分的笔试题合集,希望助大家春秋招一臂之力