【笔试刷题】VIVO-2026.03.13-改编真题
✅ 春招备战指南 ✅
💡 学习建议:
- 先尝试独立解题
- 对照解析查漏补缺
🧸 题面描述背景等均已深度改编,做法和题目本质基本保持一致。
🍹 感谢各位朋友们的订阅,你们的支持是我们创作的最大动力
🌸 目前本专栏已经上线200+套真题改编解析,后续会持续更新的
春秋招笔试机考招合集 -> 互联网必备刷题宝典🔗
VIVO-2026.03.13
这套 2026.03.13 的 VIVO 题节奏很清楚。第一题是标准状态机动态规划,只是把“卖出后冷静 k 天”这个限制推广成了可变冷静期;第二题重在把圆环规则读准,数据范围不大时直接模拟反而最稳;第三题的核心不是选区间,而是固定区间后怎样把严格递增的分配总量压到最大。
题目一:补货窗口收益规划
这题本质上还是“持有 / 不持有”两种状态。真正需要注意的是买入时不能直接接昨天的空仓状态,而要回退到 i-k-1 这一天。把这个转移写对以后,整题就是一遍线性 DP。
题目二:幸运花环淘汰赛
题面看着有点绕,其实就是一个会动态换步长的圆环淘汰游戏。重点不是上复杂数据结构,而是把“从谁开始走、走满之后删谁、删完下一轮从哪里开始”三件事说清楚。题目只给到 n <= 1000,直接模拟比硬上花哨结构更稳。
题目三:连续项目预算爬坡计划
这题最容易误判成“随便贪一个区间”。实际上连续区间和严格递增两个条件绑在一起后,固定右端点、从右向左贪心才是最自然的切法。右边尽量大,左边才有空间跟着抬起来,所以用 min(上限, 右边分配值 - 1) 反推即可。
1. 补货窗口收益规划
问题描述
L先生负责一家潮玩仓库的调仓工作。仓库每天都会给出一个进货价格数组 prices,如果当天买入一件商品,以后可以在某一天卖出获利。
不过流程上有几条限制:
- 任意时刻最多只能持有一件商品。
- 每次卖出之后,必须再等待
k天,才能重新买入。 - 可以做很多次交易,但每次交易都必须先买后卖,不能同时进行多笔交易。
给定每天的价格和冷静期 k,请计算最多可以获得多少利润。
输入格式
第一行输入两个整数 n 和 k,分别表示天数和卖出后的冷静期。
第二行输入 n 个整数 prices[i],表示第 i 天的价格。
输出格式
输出一个整数,表示最多可以获得的利润。
样例输入
7 1
1 3 5 2 6 4 1
5 1
1 2 3 0 2
1 1
1
样例输出
6
3
0
数据范围
1 <= n <= 2000000 <= k <= 2000000 <= prices[i] <= 10^9
| 样例编号 | 解释说明 |
|---|---|
| 样例 1 | 第 0 天买入,第 1 天卖出,利润为 2。因为冷静期是 1 天,所以第 2 天不能买入。接着第 3 天买入、第 4 天卖出,再赚 4。总利润为 6。 |
| 样例 2 | 一种最优方案是第 0 天买入、第 1 天卖出,利润为 1。第 2 天进入冷静期,随后第 3 天买入、第 4 天卖出,再赚 2。总利润为 3。 |
| 样例 3 | 只有一天,无法完成一笔完整交易,所以利润为 0。 |
题解
这题表面是在枚举买卖时机,真正难点在于“卖出后不能立刻再买”这个限制。只要把“当天结束后手里有没有货”拆成两个状态,问题就会清楚很多。
设:
cash[i]表示处理完第i天后,手里没有商品时能得到的最大利润。hold[i]表示处理完第i天后,手里持有一件商品时能得到的最大利润。
先看 cash[i]。
当天结束时手里没货,只可能来自两种情况:
- 昨天就没货,今天什么都不做。
- 昨天手里有货,今天把它卖掉。
所以:
cash[i] = max(cash[i-1], hold[i-1] + prices[i])
再看 hold[i]。
当天结束时手里有货,也有两种可能:
- 昨天已经持有,今天继续拿着。
- 今天刚买入。
关键是第二种情况。今天如果要买入,上一次“不持有”的状态必须至少停在第 i-k-1 天,因为卖出后还要空出 k 天冷静期。所以:
hold[i] = max(hold[i-1], cash[i-k-1] - prices[i])
当 i-k-1 < 0 时,说明之前还没有形成有效交易,买入就等价于从利润 0 开始。
整个转移只扫一遍数组,时间复杂度是 O(n),空间复杂度是 O(n)。这组数据范围下完全够用。
参考代码
- Python
import sys
input = lambda: sys.stdin.readline().strip()
def solve():
n, k = map(int, input().split())
a = list(map(int, input().split()))
# cash[i]:第 i 天结束后手里没货时的最大利润
# hold[i]:第 i 天结束后手里有货时的最大利润
cash = [0] * n
hold = [0] * n
hold[0] = -a[0]
for i in range(1, n):
# 今天结束时不持有:要么延续昨天不持有,要么今天卖出
cash[i] = max(cash[i - 1], hold[i - 1] + a[i])
# 今天想买入时,上一段不持有状态最多只能接到 i-k-1
base = 0
if i - k - 1 >= 0:
base = cash[i - k - 1]
# 今天结束时持有:要么继续持有,要么今天刚买
hold[i] = max(hold[i - 1], base - a[i])
print(cash[-1])
if __name__ == "__main__":
solve()
- Cpp
#include <bits/stdc++.h>
using namespace std;
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int n, k;
cin >> n >> k;
vector<long long> a(n);
for (int i = 0; i < n; ++i) {
cin >> a[i];
}
// cash[i]:第 i 天结束后手里没货的最好利润
// hold[i]:第 i 天结束后手里有货的最好利润
vector<long long> cash(n, 0), hold(n, 0);
hold[0] = -a[0];
for (int i = 1; i < n; ++i) {
// 卖出或者不动
cash[i] = max(cash[i - 1], hold[i - 1] + a[i]);
long long base = 0;
if (i - k - 1 >= 0) {
base = cash[i - k - 1];
}
// 持续持有或者今天买入
hold[i] = max(hold[i - 1], base - a[i]);
}
cout << cash[n - 1] << '\n';
return 0;
}
- Java
import java.io.*;
import java.util.*;
public class Main {
private static class FastScanner {
private final BufferedInputStream in = new BufferedInputStream(System.in);
private final byte[] buf = new byte[1 << 16];
private int len = 0;
private int ptr = 0;
private int read() throws IOException {
if (ptr >= len) {
len = in.read(buf);
ptr = 0;
if (len <= 0) {
return -1;
}
}
return buf[ptr++];
}
long nextLong() throws IOException {
int c;
do {
c = read();
} while (c <= ' ' && c != -1);
long sign = 1;
if (c == '-') {
sign = -1;
c = read();
}
long val = 0;
while (c > ' ') {
val = val * 10 + c - '0';
c = read();
}
return val * sign;
}
}
public static void main(String[] args) throws Exception {
FastScanner fs = new FastScanner();
int n = (int) fs.nextLong();
int k = (int) fs.nextLong();
long[] a = new long[n];
for (int i = 0; i < n; i++) {
a[i] = fs.nextLong();
}
// cash[i]:第 i 天结束后没有持仓
// hold[i]:第 i 天结束后仍然持仓
long[] cash = new long[n];
long[] hold = new long[n];
hold[0] = -a[0];
for (int i = 1; i < n; i++) {
cash[i] = Math.max(cash[i - 1], hold[i - 1] + a[i]);
long base = 0;
if (i - k - 1 >= 0) {
base = cash[i - k - 1];
}
hold[i] = Math.max(hold[i - 1], base - a[i]);
}
System.out.println(cash[n - 1]);
}
}
2. 幸运花环淘汰赛
问题描述
有 n 名玩家围成一个圆环,按逆时针方向依次编号为 0,1,2,...,n-1。每名玩家还有一个固定的幸运值 lucky[i]。
游戏从编号为 start 的玩家开始。当前步长一开始是 k,每一轮都按下面的规则进行:
- 从当前起点出发,沿逆时针方向依次向前走。
- 每经过一名仍在场的玩家,步数加
1。 - 当累计走满当前步长时,落到的那名玩家出局。
- 下一轮从这名出局玩家的下一个仍在场玩家继续开始。
- 下一轮的步长会更新为这名出局玩家自己的幸运值。
当只剩下一名玩家时,游戏结束,请输出最终幸运者的编号。
特别地,当 n = 1 时,场上只有编号 0 的玩家,游戏无需进行任何轮次,答案就是 0。
输入格式
第一行输入三个整数 n、start 和 k,分别表示玩家人数、初始起点编号和初始步长。
第二行输入 n 个整数 lucky[i],表示每名玩家的幸运值。
输出格式
输出一个整数,表示最后留下来的幸运者编号。
样例输入
3 0 1
1 2 3
样例输出
0
数据范围
1 <= n <= 10000 <= start < n1 <= k <= 10001 <= lucky[i] <= 1000
| 样例编号 | 解释说明 |
|---|---|
| 样例 1 | 初始起点是 0,步长为 1。先走到 1 号玩家,1 号出局,下一轮步长变成 lucky[1]=2。接着从 2 号继续走两步,最终 2 号出局,只剩下 0 号。 |
题解
剩余60%内容,订阅专栏后可继续查看/也可单篇购买
互联网刷题笔试宝典,这里涵盖了市面上大部分的笔试题合集,希望助大家春秋招一臂之力