【春招笔试】2025.04.12-淘天春招笔试改编题
✅ 春招备战指南 ✅
💡 学习建议:
- 先尝试独立解题(建议用时:90分钟/套)
- 对照解析查漏补缺
- 配套练习题库
🧸 题面描述背景等均已深度改编,做法和题目本质基本保持一致。
🍹 感谢各位朋友们的订阅,你们的支持是我们创作的最大动力
春秋招合集 -> 互联网必备刷题宝典🔗
淘天
题目一:商品分组最大收益
1️⃣:计算数组总和,并初始化前缀和变量
2️⃣:枚举所有可能的分割点,计算前缀和与后缀和的乘积
3️⃣:找出最大乘积值并对结果取模
难度:中等
这道题目的关键在于发现交叉乘积可以转化为前缀和与后缀和的乘积。通过线性遍历所有可能的分割点,即可在 O(n) 的时间复杂度内找到最优解。
题目二:智能调度系统优先级调整
1️⃣:使用有序集合(或优先队列)维护任务的当前优先级和下标
2️⃣:模拟每轮调整,找出当前优先级最低且下标最小的任务
3️⃣:使用全局偏移量优化实现,避免每次更新所有任务的优先级
难度:中等
这道题目的关键在于高效模拟优先级调整过程。通过维护相对优先级和全局偏移量,可以将时间复杂度优化至 O(m log n)。需要熟练运用集合或优先队列等数据结构进行高效的元素查询和更新操作。
题目三:时间线重构挑战
1️⃣:分析不同时间跨度值 k 下的交换策略
2️⃣:对于 k=1,计算排列的逆序数
3️⃣:对于 k=2,利用奇偶分组思想,计算位置差之和
4️⃣:对于 k≥3,证明可以零精力实现任意排列
难度:中等偏难
这道题目的关键在于理解不同时间跨度值 k 下的最优交换策略。需要灵活运用排列组合、奇偶性分析等数学思想,将复杂问题简化为易于计算的数学模型。时间复杂度在最坏情况下为 O(n log n)。
01. 商品分组最大收益
问题描述
小基是一位电商平台的分析师,她需要对一批商品进行分组以最大化平台收益。她有一个长度为 的商品列表,每个商品有一个价值
。她希望将这些商品分成两组:前端展示组和后端推荐组,使得两组之间的交叉收益最大化。
交叉收益定义为前端展示组中每个商品与后端推荐组中每个商品的价值乘积之和,即:
其中 是分割点(
),分割点前的商品属于前端展示组,分割点后的商品属于后端推荐组。
小基需要你的帮助来确定最大可能的交叉收益。由于收益可能非常大,请将结果对 取模后输出。
输入格式
第一行包含一个正整数 (
),表示商品的数量。
第二行包含 个整数
(
),表示每个商品的价值。
输出格式
输出一个整数,表示最大可能的交叉收益对 取模后的结果。
样例输入
5
3 2 4 1 5
样例输出
54
数据范围
样例1 | 最佳分割点为 交叉收益为 |
题解
这道题乍看起来可能需要枚举所有可能的分割点,但实际上我们可以用数学方法简化计算过程。
首先,让我们理解一下题目要求:我们需要找一个分割点 ,使得前
个元素与后
个元素之间的交叉乘积和最大。
展开这个交叉乘积和,我们可以得到:
这个公式其实就是"前缀和"乘以"后缀和"。所以,我们可以通过以下步骤解决这个问题:
- 计算整个数组的总和
- 初始化前缀和
- 遍历每个可能的分割点
(从 1 到
):
- 更新前缀和:
- 计算后缀和:
- 计算当前分割点的交叉收益:
- 更新最大收益
- 更新前缀和:
这种方法的时间复杂度是 ,空间复杂度是
(不计输入数组)。
需要注意的是,由于结果可能很大,我们需要对 取模。另外,在计算过程中应使用 64 位整数以避免溢出。
参考代码
- Python
import sys
input = lambda:sys.stdin.readline().strip()
def get_max_cross_profit():
n = int(input())
a = list(map(int, input().split()))
# 计算数组总和
tot = sum(a)
# 初始化前缀和和最大收益
psum = 0
mx = 0
# 枚举所有可能的分割点
for i in range(n-1):
psum += a[i]
ssum = tot - psum
cur = psum * ssum
mx = max(mx, cur)
# 对结果取模
return mx % 998244353
print(get_max_cross_profit())
- Cpp
#include <iostream>
#include <vector>
using namespace std;
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int n;
cin >> n;
vector<long long> a(n);
long long tot = 0;
// 读取输入并计算总和
for (int i = 0; i < n; ++i) {
cin >> a[i];
tot += a[i];
}
// 初始化前缀和和最大收益
long long psum = 0, mx = 0;
const long long MOD = 998244353;
// 枚举所有可能的分割点
for (int i = 0; i < n - 1; ++i) {
psum += a[i];
long long ssum = tot - psum;
long long cur = psum * ssum;
mx = max(mx, cur);
}
// 输出结果
cout << mx % MOD << endl;
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 n = Integer.parseInt(br.readLine().trim());
String[] tokens = br.readLine().trim().split(" ");
long[] arr = new long[n];
long tot = 0;
// 读取输入并计算总和
for (int i = 0; i < n; i++) {
arr[i] = Integer.parseInt(tokens[i]);
tot += arr[i];
}
// 初始化前缀和和最大收益
long psum = 0, mxVal = 0;
final long MOD = 998244353;
// 枚举所有可能的分割点
for (int i = 0; i < n - 1; i++) {
psum += arr[i];
long ssum = tot - psum;
long curVal = psum * ssum;
mxVal = Math.max(mxVal, curVal);
}
// 输出结果
System.out.println(mxVal % MOD);
}
}
02. 智能调度系统优先级调整
问题描述
小柯负责开发一款智能调度系统,该系统管理着一系列任务,每个任务都有一个优先级值。系统需要进行多轮优先级调整操作,每轮操作的规则如下:
- 除了当前优先级最低且最早提交的任务外,其余所有任务的优先级都会降低
个单位
- 如果有多个任务的优先级相同且最低,则选择最早提交的那个(即下标最小的)
现在小柯想知道,在进行 轮调整后,每个任务的最终优先级是多少?
输入格式
第一行包含一个整数 (
),表示测试用例的数量。
对于每个测试用例:
- 第一行包含三个正整数
、
和
(
),分别表示任务的数量、调整轮数以及每轮降低的优先级值。
- 第二行包含
个正整数
(
),表示每个任务的初始优先级。
保证所有测试用例中 的总和不超过
,
的总和不超过
。
输出格式
对于每个测试用例,输出一行包含 个整数,表示经过
轮调整后每个任务的最终优先级。
样例输入
2
6 2 3
13 11 15 20 12 11
4 1 1
1 1 1 1
样例输出
7 8 9 14 6 8
1 0 0 0
数据范围
- 所有测试用例中
的总和不超过
- 所有测试用例中
的总和不超过
样例1 第一组测试 |
初始状态: 第1轮后: 第2轮后: |
样例1 第二组测试 |
初始状态: 第1轮后: |
题解
这道题的关键是理解每轮操作的规则,并找到一种高效的方法来模拟这个过程。
最直观的想法是直接模拟每一轮操作:找出当前优先级最低且下标最小的任务,然后对其他任务的优先级进行调整。但是当任务数量和操作轮数都达到 级别时,这种方法可能会超时。
一个关键的观察是:每轮操作中,除了一个任务外,其他所有任务的优先级都会同时减少 。这意味着我们可以用一个全局偏移量来表示所有任务的优先级变化,而不是每次都去更新每个任务的值。
具体的解决方案如下:
- 使用一个集合(如有序集合)来维护当前每个任务的"相对优先级",即任务的原始优先级减去全局偏移量。
- 在每一轮操作中:
- 找出集合中最小元素(即当前优先级最低且下标最小的任务)
- 将该元素从集合中移除,增加其"相对优先级",然后重新插入集合
- 增加全局偏移量
- 最终,任务的真实优先级 = 当前"相对优先级" - 全局偏移量
这种方法的时间复杂度是 ,其中
是操作轮数,
是集合操作的复杂度。
参考代码
- Python
import sys
import heapq
input = lambda:sys.stdin.readline().strip()
def solve():
# 读取测试用例数量
t = int(input())
for _ in range(t):
# 读取任务数量、操作轮数和优先级降低值
n, m, k = map(int, input().split())
a = list(map(int, input().split()))
# 创建任务优先级队列,格式为(优先级, 下标)
pq = [(a[i], i) for i in range(n)]
heapq.heapify(pq)
# 模拟m轮操作
for _ in range(m):
# 取出优先级最低且下标最小的任务
val, idx = heapq.heappop(pq)
# 该任务优先级增加k(相当于其他任务优先级降低k)
heapq.heappush(pq, (val + k, idx))
# 还原最终结果:所有任务优先级降低m*k,除了被保护的任务
res = [a[i] - m * k for i in range(n)]
# 对于每个被保护的任务,增加相应的优先级
for val, idx in pq:
res[idx] = val - m * k
print(*res)
solve()
- Cpp
#include <iostream>
#include <queue>
#include <vector>
#include <algorithm>
using namespace std;
#define int long long
// 自定义结构体用于优先级队列
struct Task {
int priority;
int index;
// 重载小于运算符以实现最小堆
bool operator<(const Task& other) const {
if (priority == other.priority) {
剩余60%内容,订阅专栏后可继续查看/也可单篇购买
互联网刷题笔试宝典,这里涵盖了市面上大部分的笔试题合集,希望助大家春秋招一臂之力