蚂蚁金服笔试 蚂蚁金服笔试题 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等多种语言做法集合指南

