得物笔试 得物笔试题 0507
笔试时间:2025年5月7日
往年笔试合集:
第一题
n 个有礼貌的人正排好队(初始顺序为1 ~ n)准备依次通过 m, 个门,门的类型有 A、 B两种。通过这两种门时,这n 个人的顺序会发生变化,变化规则如下:A型门:走到这种门前,第一个人会有礼貌的拉开门,等到其余所有人都通过后,自己最后通过。队列中其余人的顺序不变。B型门:走到这种门前,第一个人会让给第二个人进,第二个人会让给第三个人进,以此类推。到最后,一开始排在队列的第一个人变成了最后一个进门的,一开始排在队列的最后一个人变成了第一个进门的。
输入描述
第一行输入一个正整数n,代表一共有多少人。
第二行输入一个非负整数 m,代表一共有几扇门。
接下来输入 m行数据,在 m行中的第i行输入一个字符A或者 B,代表第i扇门的类型。
输出描述
在一行中以空格分隔输出通过 m 扇门后,这些人的排列顺序
样例输入
5
4
A
A
B
A
样例输出
1
5
4
3
2
参考题解
使用一个双端队列(Deque)来模拟队伍。
对于操作 'A'(队首到队尾),根据当前队伍是否被逻辑反转,将元素从队列的一端移到另一端。
对于操作 'B'(反转),不实际移动元素,而是用一个布尔标志位来记录队伍的“观察方向”是否反转。
最后根据这个标志位,决定是正序还是逆序输出队列中的元素。
C++:
// C++ 版本
#include <bits/stdc++.h>
using namespace std;
int main(){
ios::sync_with_stdio(false);
cin.tie(nullptr);
int n, m;
cin >> n >> m;
deque<int> dq;
for(int i = 1; i <= n; i++){
dq.push_back(i);
}
bool isReversed = false;
for(int k = 0; k < m; k++){
string op;
cin >> op;
if(op == "A"){
if(!isReversed){
int v = dq.front();
dq.pop_front();
dq.push_back(v);
} else {
int v = dq.back();
dq.pop_back();
dq.push_front(v);
}
} else { // op == "B"
isReversed = !isReversed;
}
}
if(!isReversed){
for(size_t i = 0; i < dq.size(); i++){
cout << dq[i] << "\n";
}
} else {
for(auto it = dq.rbegin(); it != dq.rend(); ++it){
cout << *it << "\n";
}
}
return 0;
}
Java:
import java.util.Deque;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
int m = sc.nextInt();
Deque<Integer> dq = new LinkedList<>();
for (int i = 1; i <= n; i++) {
dq.addLast(i);
}
boolean isReversed = false;
for (int k = 0; k < m; k++) {
String op = sc.next();
if (op.equals("A")) {
if (!isReversed) {
int val = dq.removeFirst();
dq.addLast(val);
} else {
int val = dq.removeLast();
dq.addFirst(val);
}
} else { // op.equals("B")
isReversed = !isReversed;
}
}
StringBuilder resultBuilder = new StringBuilder();
if (n > 0) { // n is guaranteed to be >= 1 by constraints
if (!isReversed) {
Iterator<Integer> iterator = dq.iterator();
resultBuilder.append(iterator.next()); // First element
while (iterator.hasNext()) {
resultBuilder.append("\n").append(iterator.next());
}
} else {
Iterator<Integer> descendingIterator = dq.descendingIterator();
resultBuilder.append(descendingIterator.next()); // First element from reversed perspective
while (descendingIterator.hasNext()) {
resultBuilder.append("\n").append(descendingIterator.next());
}
}
}
System.out.println(resultBuilder.toString());
sc.close();
}
}
Python:
# Python 版本
import sys
from collections import deque
def main():
data = sys.stdin.read().split()
it = iter(data)
n = int(next(it))
m = int(next(it))
dq = deque(range(1, n+1))
is_reversed = False
for _ in range(m):
op = next(it)
if op == "A":
if not is_reversed:
dq.append(dq.popleft())
else:
dq.appendleft(dq.pop())
else: # op == "B"
is_reversed = not is_reversed
out = []
if not is_reversed:
out.extend(str(x) for x in dq)
else:
out.extend(str(x) for x in reversed(dq))
sys.stdout.write("\n".join(out))
if __name__ == "__main__":
main()
第二题
小牛拥有一个魔法,可以对一个正整数a的十进制数字进行任意重新排列。随后,他将排列后的数字序列分成b段,形成b个子数字。具体地要求如下: 每一段必须是排列后数字序列中的连续子串,b段连起来恰好能够完整的拼回重新排列后的数字a‘不得遗漏或重叠。每一段至少包含1位数字(即不能出现空段);允许某段生成的子数字为0,但不允许出现多余的前导零。请你求出分成b段后,这b个子数之和的最大可能值。
【名词解释】连续子串为从原数字序列中,连续的选择一段数位(可以全选)得到的新字符串。除整数0外,任何以0开头的多位数字的的首个0,都叫做多余的前导零。例如,01中的0是多余的前导零,而 101 中的 0不是前导零。0 本身没有多余的前导零。
输入描述
在一行上输入两个整数 a,b,分别表示原始整数与分段数。
b范围的意义是:保证b不超过整数 a 的十进制长度。
输出描述
输出一个整数,表示将整数 a 的数字打乱顺序后分为b段所得各子数之和的最大值。
样例输入
13 1
样例输出
31
参考题解
将输入整数 a 的各位数字提取出来,并按降序排列,形成一个新的数字字符串。这是因为要使得分割后的数字之和最大,通常将较大的数字放在高位或独立成较大的数。使用动态规划。定义 dp[i][j] 表示将排序后数字字符串的前 i 个字符分割成 j 段所能得到的最大和。遍历所有可能的分割点和段数,通过 dp[i][j] = max(dp[k][j-1] + value(substring(k, i))) 来更新 dp 表,其中 value(substring(k, i)) 是从第 k 个字符到第 i-1 个字符组成的子数字串的值(注意处理前导零)。最终结果为 dp[length_of_string][b]。
C++:
// C++ 版本
#include <bits/stdc++.h>
using namespace std;
long long parseValue(const string &s) {
// 去掉多余前导零
int i = 0, n = s.size();
if (n > 1 && s[0] == '0') {
while (i < n - 1 && s[i] == '0') i++;
}
return stoll(s.substr(i));
}
int main(){
ios::sync_with_stdio(false);
cin.tie(nullptr);
long long a_val;
int b_segments;
cin >> a_val >> b_segments;
string s = to_string(a_val);
sort(s.begin(), s.end());
// 逆序得到最终字符串
reverse(s.begin(), s.end());
int n_len = s.size();
const long long NEG_INF = LLONG_MIN / 4;
vector<vector<long long>> dp(n_len + 1, vector<long long>(b_segments + 1, NEG_INF));
dp[0][0] = 0;
for (int k = 1; k <= b_segments; k++) {
for (int i = k; i <= n_len; i++) {
long long best = NEG_INF;
for (int p = k - 1; p < i; p++) {
long long prev = dp[p][k - 1];
if (prev > NEG_INF / 2) {
string segment = s.substr(p, i - p);
long long val = parseValue(segment);
best = max(best, prev + val);
}
}
dp[i][k] = best;
}
}
cout << dp[n_len][b_segments] << "\n";
return 0;
}
Java:
import java.util.Arrays;
import java.util.Scanner;
public class Main {
private static long parseValue(String s) {
if (s.length() > 1 && s.charAt(0) == '0') {
int i = 0;
while (i < s.length() - 1 && s.charAt(i) == '0') {
i++;
}
return Long.parseLong(s.substring(i));
}
return Long.parseLong(s);
}
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
long a_val = scanner.nextLong();
剩余60%内容,订阅专栏后可继续查看/也可单篇购买
2025打怪升级记录,大厂笔试合集 C++, Java, Python等多种语言做法集合指南
查看25道真题和解析