蚂蚁金服笔试 蚂蚁金服笔试题 0824
笔试时间:2025年8月24日
往年笔试合集:
第一题:牛
在一副牌中,数字 1~10 各有 4 张。发牌员先后给 Tk 与 wida 各发 5 张牌,此时牌堆还剩 30 张牌。两名玩家按照下列规则决定胜负:
若两人都无法从自己的 5 张手牌中选出 3 张牌,使得它们之和为 10 的倍数,则比较各自手牌中的最大数字,数字较大者获胜;若最大数字相同,则本局平局;
若仅有一人可以选出这样的 3 张牌,则该名玩家直接获胜;
若两人都可以选出这样的 3 张牌,则各自都选择一种方案,使得余下 2 张牌数字之和为 x 时,比较 ((x - 1) mod 10) + 1 的大小(即把 x mod 10 中的 0 视作 10),值较大者获胜;若两值相同,则本局平局。
现给出两名玩家的手牌,请判断每局比赛的结果。
输入描述
每个测试文件包含多组独立测试数据。第一行输入一个整数 T(1 ≤ T ≤ 10 的 4 次方)表示测试数据组数,每组测试数据的格式如下:
第一行输入 5 个整数 a₁,a₂,…,a₅(1 ≤ aᵢ ≤ 10),表示 Tk 的手牌;
第二行输入 5 个整数 b₁,b₂,…,b₅(1 ≤ bᵢ ≤ 10),表示 wida 的手牌。
保证输入合法:同一种数字的牌在两人手牌中的总数量不超过 4。
输出描述
对于每一组测试数据,新起一行输出比赛结果:
若 Tk 获胜,输出 Tk;
若 wida 获胜,输出 wida;
若平局,输出 emm。
样例输入
3
10 1 9 2 3
6 6 6 6 1
6 6 6 6 1
10 1 9 2 3
3 3 3 1 1
3 2 2 1 1
样例输出
Tk
wida
emm
参考题解
每人 5 张牌,若能从中挑 3 张使其和为 10 的倍数,则称“有牛”。余下两张之和 mod 10 得到牛数(0 记为 10)。规则:仅一人有牛 ⇒ 他赢;都有牛 ⇒ 比牛数,大者赢,相同平局;都无牛 ⇒ 比最大牌,大者赢,相同平局。关键观察:若存在三张和能整除 10,则余下两张的和 ≡ 总和 mod 10,因此牛数唯一由总和决定。无需枚举取最大。做法:判断是否存在三张和 %10==0;若有牛:牛数 = (总和 % 10) 或 10;若无牛:记录最大单牌;按优先级比较结果。复杂度:每手枚举 10 种三张组合,O(1)。
C++:
#include <bits/stdc++.h> using namespace std; struct Stat { bool n; // 是否存在任意3个数之和能被10整除 int b; // 在满足条件的所有三元组里,剩余两个数之和的 (mod 10,0记为10) 的最大值 int m; // 数组最大值 }; static inline Stat f1(const array<int,5>& h) { Stat res{false, -1, *max_element(h.begin(), h.end())}; int tot = 0; for (int x : h) tot += x; // 遍历所有 C(5,3) = 10 个三元组 for (int i = 0; i < 5; ++i) for (int j = i + 1; j < 5; ++j) for (int k = j + 1; k < 5; ++k) { int s = h[i] + h[j] + h[k]; if (s % 10 == 0) { res.n = true; int rem = tot - s; // 剩余两个数之和 int v = rem % 10; if (v == 0) v = 10; if (v > res.b) res.b = v; } } return res; } static inline string g(const array<int,5>& a, const array<int,5>& b) { Stat s1 = f1(a), s2 = f1(b); if (s1.n && !s2.n) return "Tk"; if (s2.n && !s1.n) return "wida"; if (s1.n && s2.n) { if (s1.b > s2.b) return "Tk"; if (s1.b < s2.b) return "wida"; return "emm"; } if (s1.m > s2.m) return "Tk"; if (s1.m < s2.m) return "wida"; return "emm"; } int main() { ios::sync_with_stdio(false); cin.tie(nullptr); int T; if (!(cin >> T)) return 0; while (T--) { array<int,5> a, b; for (int i = 0; i < 5; ++i) cin >> a[i]; for (int i = 0; i < 5; ++i) cin >> b[i]; cout << g(a, b) << '\n'; } return 0; }
Java:
import java.io.*; import java.util.*; public class Main { static class Stat { boolean n; // 是否存在三元组之和%10==0 int b; // 满足条件时剩余两数之和的 (mod 10,0记为10) 的最大值 int m; // 数组最大值 Stat(boolean n, int b, int m) { this.n = n; this.b = b; this.m = m; } } static Stat f1(int[] h) { int m = Arrays.stream(h).max().orElse(Integer.MIN_VALUE); int tot = 0; for (int x : h) tot += x; boolean n = false; int best = -1; // 遍历所有 5C3 = 10 个三元组 for (int i = 0; i < 5; i++) { for (int j = i + 1; j < 5; j++) { for (int k = j + 1; k < 5; k++) { int s = h[i] + h[j] + h[k]; if (s % 10 == 0) { n = true; int rem = tot - s; // 剩余两数之和 int v = rem % 10; if (v == 0) v = 10; if (v > best) best = v; } } } } return new Stat(n, best, m); } static String g(int[] a, int[] b) { Stat s1 = f1(a), s2 = f1(b); if (s1.n && !s2.n) return "Tk"; if (s2.n && !s1.n) return "wida"; if (s1.n && s2.n) { if (s1.b > s2.b) return "Tk"; if (s1.b < s2.b) return "wida"; return "emm"; } if (s1.m > s2.m) return "Tk"; if (s1.m < s2.m) return "wida"; return "emm"; } // 简单快读 static class FS { BufferedInputStream in = new BufferedInputStream(System.in); byte[] buf = new byte[1 << 16]; int ptr = 0, len = 0; int read() throws IOException { if (ptr >= len) { len = in.read(buf); ptr = 0; if (len <= 0) return -1; } return buf[ptr++]; } String next() throws IOException { StringBuilder sb = new StringBuilder(); int c; do { c = read(); } while (c <= ' ' && c != -1); if (c == -1) return null; while (c > ' ') { sb.append((char)c); c = read(); } return sb.toString(); } int nextInt() throws IOException { return Integer.parseInt(next()); } } public static void main(String[] args) throws Exception { FS fs = new FS(); String tok = fs.next(); if (tok == null) return; int T = Integer.parseInt(tok); StringBuilder out = new StringBuilder(); for (int tc = 0; tc < T; tc++) { int[] a = new int[5]; int[] b = new int[5]; for (int i = 0; i < 5; i++) a[i] = fs.nextInt(); for (int i = 0; i < 5; i++) b[i] = fs.nextInt(); out.append(g(a, b)).append('\n'); } System.out.print(out.toString()); } }
Python:
import sys from itertools import combinations as cmb def f1(h): n = False b = -1 for c in cmb(range(5), 3): s = sum(h[i] for i in c) if s % 10 == 0: n = True r = [i for i in range(5) if i not in c] v = (h[r[0]] + h[r[1]]) % 10 v = 10 if v == 0 else v if v > b: b = v m = max(h) return n, b, m def g(a, b): x1, y1, z1 = f1(a) x2, y2, z2 = f1(b) if x1 and not x2: return "Tk" if x2 and not x1: return "wida" if x1 and x2: if y1 > y2: return "Tk" if y1 < y2: return "wida" return "emm" if z1 > z2: return "Tk" if z1 < z2: return "wida" return "emm" def main(): r = [] t = int(sys.stdin.readline()) for _ in range(t): a1 = list(map(int, sys.stdin.readline().split())) a2 = list(map(int, sys.stdin.readline().split())) r.append(g(a1, a2)) sys.stdout.write("\n".join(r)) if __name__ == "__main__": main()
第二题:闪避
笨蛋同学正在一款游戏中打 boss,虽然她拥有无限血量,但她发现闪避后的反击伤害可能比直接攻击更高。
游戏共进行 n 轮操作,每轮可选以下两种操作之一:
攻击 boss,造成 aᵢ点伤害;
闪避 boss 的攻击,本轮不造成伤害,但若下轮选择攻击,则此次攻击造成 bᵢ点伤害。
输入描述
第一行输入一个整数 n(1 ≤ n ≤ 2×10 的 5 次方),表示游戏轮数;
第二行输入 n 个整数 a₁,a₂,…,aₙ(1 ≤ aᵢ ≤ 10 的 9 次方),表示每轮直接攻击伤害;
第三行输入 n 个整数 b₁,b₂,…,bₙ(1 ≤ bᵢ ≤ 10 的 9 次方),表示每轮闪避后下轮可造成的伤害。
输出描述
输出一个正整数,表示在最优操作下可造成的最大总伤害。
样例输入
6
1 1 4 5 1 4
1 9 1 9 8 1
样例输出
23
参考题解
我们可以用两个变量来维护当前的最大伤害:attack_dp[i]:在第 i 轮选择攻击所能获得的最大伤害。dodge_dp[i]:在第 i 轮选择闪避所能获得的最大伤害。然而,我们发现对于每一轮,我们只关心上一轮的状态,所以可以使用两个变量来代替整个数组,从而优化空间复杂度。我们用 x 代表在当前轮选择攻击所能获得的最大总伤害,用 y 代表选择闪避所能获得的最大总伤害。对于第 i 轮(从 1 开始计数),我们可以从第 i-1 轮的状态转移而来:在第 i 轮选择攻击:如果第 i-1 轮是攻击,那么第 i 轮只能
剩余60%内容,订阅专栏后可继续查看/也可单篇购买
2025打怪升级记录,大厂笔试合集 C++, Java, Python等多种语言做法集合指南