蚂蚁笔试 蚂蚁笔试题 0821
笔试时间:2025年8月21日
往年笔试合集:
第一题:寻找符合条件的数组
给定一个正整数 n。请你找到一个长度至少为 2 的数组 a,使得数组 a 中仅含 1 和合数,且 a 中所有元素的和为 n。如果有多个满足条件的 a,请输出长度最短的。如果有多个长度最短的 a,你可以输出任意一个。注意,自测运行功能可能因此返回错误结果,请自行检查答案正确性。
输入描述
每个测试文件均包含多组测试数据。第一行输入一个整数 T (1 ≤ T ≤ 10^3) 代表数据组数,每组测试数据描述如下:
输入一行一个正整数 n (2 < n ≤ 10^18)。
输出描述
对于每组测试数据,先输出一行一个正整数 k,表示 a 的长度。在第二行输出 k 个整数,表示 a 中的元素。如果存在多个解法方案,您可以输出任意一个,系统会自动判定是否正确。注意,自测运行功能可能因此返回错误结果,请自行检查答案正确性。
样例输入
3
8
10
2
样例输出
2
4 4
2
1 9
2
1 1
参考题解
当n为偶数时,答案应该是4和n-4; 当n为奇数时,答案应该是1和n-1; 需要暴力特判一下n=2,3,4,6的情况。
C++:
#include <bits/stdc++.h> using namespace std; int main() { ios::sync_with_stdio(false); cin.tie(nullptr); long long t; if (!(cin >> t)) return 0; while (t--) { long long n; cin >> n; if (n == 2) { cout << "2\n1 1\n"; } else if (n == 3) { cout << "3\n1 1 1\n"; } else if (n == 4) { cout << "4\n1 1 1 1\n"; } else if (n == 6) { cout << "3\n4 1 1\n"; } else { if (n % 2 == 0) { cout << "2\n4 " << (n - 4) << "\n"; } else { cout << "2\n" << (n - 1) << " 1\n"; } } } return 0; }
Java:
import java.io.*; import java.util.*; public class Main { public static void main(String[] args) throws Exception { BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); PrintWriter out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(System.out))); int t = Integer.parseInt(br.readLine().trim()); for (int _case = 0; _case < t; _case++) { long n = Long.parseLong(br.readLine().trim()); if (n == 2) { out.println("2"); out.println("1 1"); } else if (n == 3) { out.println("3"); out.println("1 1 1"); } else if (n == 4) { out.println("4"); out.println("1 1 1 1"); } else if (n == 6) { out.println("3"); out.println("4 1 1"); } else { if (n % 2 == 0) { out.println("2"); out.println("4 " + (n - 4)); } else { out.println("2"); out.println((n - 1) + " 1"); } } } out.flush(); } }
Python:
t = int(input().strip()) res = [] for _ in range(t): n = int(input().strip()) if n == 2: print("2\n1 1") elif n == 3: print("3\n1 1 1") elif n == 4: print("4\n1 1 1 1") elif n == 6: print("3\n4 1 1") else: if n % 2 == 0: print(f"2\n4 {n - 4}") else: print(f"2\n{n - 1} 1")
第二题:文本分类预测
读取数据:输入为JSON格式,包含训练集和测试集:"train": 列表,每个元素为["文本", 标签],其中标签为0或1"test": 列表,仅包含文本预处理
i. 将文本统一转换为小写
ii. 去除首尾空白字符,再用单空格重新连接,消除多余空格特征工程
使用CountVectorizer与TfidfTransformer处理特征:先fit + transform训练集再对测试集仅执行transform模型训练 & 预测在训练集的TF-IDF特征上拟合LogisticRegression对测试集计算正类概率,概率≥0.5则预测为1,否则为0输入描述JSON格式数据,结构如下:
输入描述
JSON格式数据,结构如下:
{
"train": [["文本1", 标签1], ["文本2", 标签2], ...],
"test": ["文本1", "文本2", ...]
}
其中,训练集数据量≥4,每条数据包含文本和标签(0或1);测试集仅包含文本。
输出描述
单行JSON数组,元素为0或1,顺序与测试集文本对应,如[1,0,1]。
样例输入
{"train":[["good movie",1],["great film",1],["bad movie",0],["terible flm",0]],"test":["good film","bad film"]}
样例输出
[1, 0]
参考题解
读取JSON输入数据,分离训练集和测试集。对文本进行预处理:转换为小写,去除首尾空白,用单空格连接消除多余空格。特征工程:使用CountVectorizer将训练集文本转换为词频矩阵,再通过TfidfTransformer转换为TF-IDF特征;对测试集文本执行相同的特征转换(复用训练集的拟合参数)。模型训练:在训练集的TF-IDF特征上拟合LogisticRegression(设置random_state=42)。预测:计算测试集的正类概率,根据≥0.5则为1、否则为0的规则生成预测结果,输出JSON数组。
Python:
import json from sklearn.feature_extraction.text import CountVectorizer, TfidfTransformer from sklearn.linear_model import LogisticRegression input_data = json.loads(input()) train_data = input_data["train"] test_texts = input_data["test"] def preprocess_text(text): return" ".join(text.lower().strip().split()) processed_train_texts = [preprocess_text(item[0]) for item in train_data] train_labels = [int(item[1]) for item in train_data] processed_test_texts = [preprocess_text(text) for text in test_texts] count_vectorizer = CountVectorizer() tfidf_transformer = TfidfTransformer() train_word_counts = count_vectorizer.fit_transform(processed_train_texts) train_tfidf = tfidf_transformer.fit_transform(train_word_counts) log_reg = LogisticRegression(random_state=42) log_reg.fit(train_tfidf, train_labels) test_word_counts = count_vectorizer.transform(processed_test_texts) test_tfidf = tfidf_transformer.transform(test_word_counts) positive_probs = log_reg.predict_proba(test_tfidf)[:, 1] predictions = [1if prob >= 0.5else0for prob in positive_probs] print(json.dumps(predictions))
第三题
TK 有一个长度为 n 的数组 {a1, a2, …, an},其中每个元素 ai 等于 -1 或 1;
你需要与 TK 进行 m 轮游戏,每轮游戏相互独立(即数组的改变并不会影响其他轮次);
在每一轮游戏中,TK 会在当前数组中选择一个区间 [l, r],并记录
- S = ∑ ai
- 随后将区间 [l, r] 从数组中删除,剩余元素按原顺序拼接;
你的任务是:在新的数组中找到一个区间 [l1, r1],满足
- 区间长度与被删除区间相同,即 r1 - l1 = r - l;
- ∑ ai > S。
如果存在多个满足条件的区间,可以输出任意一个;如果不存在,则输出 -1。
输入描述
每个测试文件均包含多组测试数据:
- 第一行输入一个整数 T (1 ≤ T ≤ 10),表示测试组数;除此之外,保证单个测试文件的 ∑ n、∑ m 及所有被删除区间长度之和均不超过 10^5;
接下来对于每组测试数据:
- 第一行输入两个整数 n, m (1 ≤ n, m ≤ 10^5),分别表示数组长度和游戏轮次;
- 第二行输入 n 个整数 a1, a2, …, an (ai ∈ {-1, 1}),表示初始数组;
- 此后 m 行,每行输入两个整数 l 和 r (1 ≤ l ≤ r ≤ n),表示 TK 选择的删除区间。
输出描述
对于每组测试数据,输出 m 行,每行对应一轮游戏的答案;如果无解,输出 -1;
否则,输出两个整数 l₁ 和 r₁ (1 ≤ l₁ ≤ r₁ ≤ n - (r - l + 1)),表示你选取的区间。
样例输入
1
5 2
-1 1 1 -1 1
3 4
1 3
样例输出
2 3
-1
参考题解
说明:第一轮游戏,S = 0,删除后数组变为 {-1, 1, 1},区间 [2, 3] 满足答案。第二轮游戏删除后数组变为 {-1, 1},长度小于 3 一定无解。离线处理:题目中的每轮游戏相互独立,因此我们不必按输入顺序处理。可以将所有查询先读进来,根据一个高效的策略重新排序处理,这种方法叫作“离线”。按长度分组:最有效的策略是按删除区间的长度 k 分组。因为同一长度 k 的所有查询,都需要寻找一个长度也为 k 的新区间,这使得我们可以为每个 k 值进行一次性的预处理,然后快速回答该长度的所有查询。预处理加速:对于一个固定的长度 k,我们可以花 O(n) 时间预处理两样东西:一个数组 Sums_k,Sums_k[i] 存原数组中从 i 开始,长度为 k 的区间的和。基于 Sums_k,再计算出它的前缀最大值和后缀最大值数组。这能让我们在 O(1) 时间内查出任意前缀 [1...i] 或后缀 [j...n] 中的最大区间和及其位置。分情况求解:对于每个查询 (l, r)(长度为 k),最优解只可能来自三种情况:左侧:完全在 l 左边。利用预处理的“前缀最大值”可 O(1) 找到。右侧:完全在 r 右边。利用预处理的“后缀最大值”可 O(1) 找到。跨越:由 l 左侧的后缀和 r 右侧的前缀拼接而成。这部分没有捷径,直接遍历 k-1 种拼接可能,复杂度为 O(k)。
C++:
#include <iostream> #include <vector> #include <numeric> #include <map> #include <algorithm> using namespace std; const int INF = 1e9; struct Query { int id; int l, r, k; }; struct MaxInfo { int val; int index; bool operator>(const MaxInfo& other) const { if (val != other.val) { return val > other.val; } return index < other.index; // 优先选下标小的 } }; void solve() { int n, m; cin >> n >> m; vector<int> a(n + 1); vector<long long> p(n + 1, 0); for (int i = 1; i <= n; ++i) { cin >> a[i]; p[i] = p[i - 1] + a[i]; } map<int, vector<Query>> queries_by_len; for (int i = 0; i < m; ++i) { int l, r; cin >> l >> r; queries_by_len[r - l + 1].push_back({i, l, r, r - l + 1}); } vector<pair<int, int>> answers(m); for (auto const& [k, q_list] : queries_by_len) { if (n - k < k) { // 剩余数组长度不足k,无法找到 for (const auto& q : q_list) { answers[q.id] = {-1, -1}; } continue; } int sums_len = n - k + 1; vector<MaxInfo> sums_k(sums_len + 1); for (int i = 1; i <= sums_len; ++i) { sums_k[i] = {(int)(p[i + k - 1] - p[i - 1]), i}; } vector<MaxInfo> prefix_max(sums_len + 1); prefix_max[0] = {-INF, -1}; for (int i = 1; i <= sums_len; ++i) { if (sums_k[i] > prefix_max[i - 1]) { prefix_max[i] = sums_k[i]; } else { prefix_max[i] = prefix_max[i - 1]; } } vector<MaxInfo> suffix_max(sums_len + 2); suffix_max[sums_len + 1] = {-INF, -1}; for (int i = sums_len; i >= 1; --i) { if (sums_k[i] > suffix_max[i + 1]) { suffix_max[i] = sums_k[i]; } else { suffix_max[i] = suffix_max[i + 1]; } } for (const auto& q : q_list) { int S = p[q.r] - p[q.l - 1]; MaxInfo best_res = {S, -1}; int best_l1 = -1, best_r1 = -1
剩余60%内容,订阅专栏后可继续查看/也可单篇购买
2025打怪升级记录,大厂笔试合集 C++, Java, Python等多种语言做法集合指南