得物笔试 得物笔试题 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等多种语言做法集合指南