蚂蚁笔试 蚂蚁笔试题 20260315 春招实习笔试真题
笔试时间:2026年3月15日
往年笔试合集:
第一题:木棍搭房子
题目
小明想用木棍搭一个"房子"形状:下部是一个长方形,上部是一个等腰三角形,且两者共用一条边(即长方形的上边同时作为三角形的底边,三角形除底边外的两条边要相等)。他手上有一堆木棍(每根木棍的长度为正整数),每根木棍最多使用一次。请你判断,是否能从中挑出若干根,恰好拼成这样的"房子"。
输入描述
输入一行一个整数 n (6 ≤ n ≤ 10^5),表示木棍数量。
输入第二行包含 n 个整数 a₁, a₂, …, aₙ (1 ≤ aᵢ ≤ 10^5),表示每根木棍的长度。
输出描述
输出一行:若能用这些木棍拼出"房子",输出 YES;否则输出 NO。
样例输入1
6 4 4 3 3 5 5
样例输出1
YES
样例说明1
可取两根 4 作为长方形上下边,其中上边与三角形底边共用一根、两根 3 作为长方形左右边、两根 5 作为等腰三角形的两腰。
样例输入2
6 4 4 3 3 2 1
样例输出2
NO
参考题解
解题思路:
假设我们随便找到了 3 对木棍,把它们的长度从小到大排列:A ≤ B ≤ C。我们把最长的一对 C 拿去做两腰,把最短的一对 A 拿去做底边。因为 C ≥ A,且木棍长度都是正数,所以 2C > A 永远成立(等腰三角形条件)。
最终结论:只要统计木棍出现的频率,算出总共有多少对(每 2 根算 1 对)。只要对数 ≥ 3,直接输出 YES;凑不够 3 对,输出 NO。
C++
#include <iostream>
#include <vector>
using namespace std;
int main() {
ios::sync_with_stdio(false);
cin.tie(NULL);
int n;
if (cin >> n) {
vector<int> counts(100005, 0);
for (int i = 0; i < n; ++i) {
int a;
cin >> a;
counts[a]++;
}
int total_pairs = 0;
for (int i = 1; i <= 100000; ++i) {
total_pairs += counts[i] / 2;
}
if (total_pairs >= 3) {
cout << "YES\n";
} else {
cout << "NO\n";
}
}
return 0;
}
Java
import java.util.*;
import java.io.*;
public class Main {
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
int n = Integer.parseInt(br.readLine().trim());
int[] counts = new int[100005];
StringTokenizer st = new StringTokenizer(br.readLine());
for (int i = 0; i < n; i++) {
int a = Integer.parseInt(st.nextToken());
counts[a]++;
}
int totalPairs = 0;
for (int i = 1; i <= 100000; i++) {
totalPairs += counts[i] / 2;
}
System.out.println(totalPairs >= 3 ? "YES" : "NO");
}
}
Python
import sys
from collections import Counter
input = sys.stdin.readline
def solve():
n = int(input())
a = list(map(int, input().split()))
cnt = Counter(a)
total_pairs = 0
for v in cnt.values():
total_pairs += v // 2
print("YES" if total_pairs >= 3 else "NO")
solve()
第二题:好的二元组
题目
给定一个长度为 n 的数组 {a₁, a₂, …, aₙ},初始时,对于所有 1 ≤ i ≤ n 均有 aᵢ = i。定义一对二元组(有序对)(i, j) 满足 1 ≤ i, j ≤ n,i ≠ j;若 aᵢ ≤ m 且 aⱼ > m,则称 (i, j) 是一个好的二元组。
你可以进行如下操作任意次(包括 0 次):选择一个下标 i,将 aᵢ 修改为 n − aᵢ + 1。
请计算在最优操作后,数组中最多能有多少个不同的好的二元组。
输入描述
每个测试文件均包含多组测试数据。第一行输入一个整数 T (1 ≤ T ≤ 10^4) 表示数据组数,每组测试数据描述如下:
一行输入两个整数 n, m (1 ≤ n, m ≤ 10^9) 表示数组长度与阈值。
输出描述
对于每一组测试数据,新起一行,输出一个整数,表示在最优操作后,最多存在的不同好的二元组数量。
样例输入
4 5 2 4 1 1 1 3 10
样例输出
6 4 0 0
样例说明
对于第二组测试数据初始数组为 {1,2,3,4},选择下标 4,数组变为 {1,2,3,1}。此时数组满足条件的二元组有 (1,2), (1,3), (4,2), (4,3)。
可以证明不存在其他操作使得满足条件的二元组数量更多。
参考题解
解题思路:
一个好的二元组必须由一个 ≤ m 的数和一个 > m 的数配对。假设最终数组里有 A 个数 ≤ m,那么剩下的 n - A 个数就必然 > m,二元组的总对数就是 A × (n - A)。根据数学常识,当两数之和(n)固定时,要想让它们的乘积最大,A 必须尽可能接近 n / 2。
对于任意位置 i,它的值只能在 i 和 n - i + 1 之间二选一。这说明 A 的数量有一个固定的范围 [A_min, A_max]:
- 求 A_min(必须 ≤ m 的保底个数):如果某对选项 i 和 n - i + 1 两个都 ≤ m,那无论怎么操作,最终结果肯定 ≤ m,这决定了 A 的下限。
- 求 A_max(可能 ≤ m 的极限个数):如果某对选项中至少有一个 ≤ m,我们就贪心地全选 ≤ m 的那个,这决定了 A 的上限。
拿到取值范围 [A_min, A_max] 后,在这个闭区间里找一个最接近中点 n / 2 的合法整数,作为最终的最优 A。
C++
#include <iostream>
#include <algorithm>
using namespace std;
void solve() {
long long n, m;
cin >> n >> m;
long long A_min = max(0LL, min(n, 2LL * m
剩余60%内容,订阅专栏后可继续查看/也可单篇购买
2025打怪升级记录,大厂笔试合集 C++, Java, Python等多种语言做法集合指南
查看34道真题和解析