关注我们,每天更新大厂最新笔试题解析
前言
文末给大家推荐一下我们的活动,针对校招笔面试全覆盖的全程真一对一的提高,参加活动前会给你安排一个全面的摸底,摸底后会针对你的情况进行分析和对于参加活动的介绍,然后你再决定是否参加!
在线做题链接:https://niumacode.com/
这三道题目本质上都是数学思维题与贪心算法,所以找到角度还是比较简单的,算是蚂蚁秋招到现在最简单的一场笔试了。
这种难度的笔试大家还是要尽量争取ak的。
在线做题链接:https://niumacode.com/
题意
小明想用木棍搭一个 “房子” 形状:下部是一个长方形,上部是一个等腰三角形,且两者共用一条边(即长方形的上边同时作为三角形的底边,三角形除底边外的两条边要相等)。他手上有一堆木棍(每根木棍的长度为正整数),每根木棍最多使用一次。请你判断,是否能从中挑出若干根,恰好拼成这样的 “房子”。
输入描述
输入一行一个整数 n (6≤n≤10的五次方),表示木棍数量。输入第二行包含 n
个整数 a1,a2,…,an (1≤ai≤10的五次方)
,表示每根木棍的长度。
输出描述
输出一行:若能用这些木棍拼出 “房子”,输出 YES;否则输出 NO。
示例1
输入:
6
4 4 3 3 5 5
输出:
YES
说明:
可取两根 4 作为长方形上下边,其中上边与三角形底边共用一根、两根 3 作为长方形左右边、两根 5 作为等腰三角形的两腰,且两腰之和大于底边可以构造等腰三角形,满足要求,输出 YES。
示例2输入:
6
4 4 3 3 2 1
输出:
NO
思路与代码
假设我们随便找到了 3 对木棍,把它们的长度从小到大排列:A<=B<=C
我们极其“贪心”地把最长的一对 C 拿去做两腰,把最短的一对 A 拿去做底边。
因为 C>=A,且木棍长度都是正数,所以 2C > A 永远绝对成立!
最终结论:只要统计木棍出现的频率,算出总共有多少对(每 2 根算 1 对)。只要对数 >=3,什么都不用管,闭眼输出 YES;凑不够 3 对,输出 NO。
#include <iostream>
#include <vector>
using namespace std;
int main() {
// 优化标准输入输出流,提升运行速度
ios::sync_with_stdio(false);
cin.tie(NULL);
int n;
if (cin >> n) {
// 因为 a_i 最大为 100000,开一个大小为 100005 的数组来统计频率
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; // 每 2 根相同的木棍算 1 对
}
// 只要总对数大于等于 3,就一定能拼成房子
if (total_pairs >= 3) {
cout << "YES\n";
} else {
cout << "NO\n";
}
}
return 0;
}
在线做题链接:https://niumacode.com/
题意
给定一个长度为 n的数组 {a1,a2,…,an},初始时,对于所有 1≤i≤n均有 ai=i。定义一对二元组(有序对)(i,j) 满足 1≤i,j≤n, i=j;若 ai≤m 且 aj>m,则称 (i,j) 是一个好的二元组。你可以进行如下操作任意次(包括 0 次):选择一个下标 i,将 ai 修改为 n−ai+1
请计算在最优操作后,数组中最多能有多少个不同的好的二元组。
输入描述
每个测试文件均包含多组测试数据。第一行输入一个整数 T (1≤T≤104)
表示数据组数,每组测试数据描述如下:
一行输入两个整数 n,m (1≤n,m≤109)表示数组长度与阈值。
输出描述
对于每一组测试数据,新起一行,输出一个整数,表示在最优操作后,最多存在的不同好的二元组数量。
示例1
输入:
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,我们就贪心地全选 <=那个。这决定了 A的上限。
贪心取点:在区间内找最优解
拿到了取值范围 [A_{min}, A_{max}]后,我们只需要在这个闭区间里,找一个最接近中点 n / 2的合法整数,作为最终的最优 A:
如果区间最大值还够不到 n / 2,那就取 A_{max}。
如果区间最小值已经超过了 n / 2,那就取 A_{min}。
如果 n / 2刚好包在区间里,那就完美了,直接取 n / 2。
#include <iostream>
#include <algorithm>
using namespace std;
void solve() {
long long n, m;
cin >> n >> m;
// 计算 A (即最终 <=m 的元素个数) 的理论最小和最大值
long long A_min = max(0LL, min(n, 2LL * m - n));
long long A_max = min(n, 2LL * m);
// 我们希望 A 尽可能接近 n / 2
long long best_A;
long long half = n / 2;
// 根据二次函数在闭区间上的最值性质,寻找最接近 n/2 的合法 A
if (A_max <= half) {
// 如果能达到的最大值还不到中点,就取最大值
best_A = A_max;
} else if (A_min >= half + (n % 2)) {
// 如果能达到的最小值已经超过了中点,就取最小值
// 注意:如果是奇数 n,中点有两个,half 和 half + 1 效果一样
best_A = A_min;
} else {
// 中点落在 [A_min, A_max] 区间内,直接取中点可以达到绝对最优
best_A = half;
}
// 输出最多的二元组数量
cout << best_A * (n - best_A) << "\n";
}
int main() {
// 优化标准输入输出,防止大量数据导致 TLE
ios_base::sync_with_stdio(false);
cin.tie(NULL);
int t;
if (cin >> t) {
while (t--) {
solve();
}
}
return 0;
}
在线做题链接:https://niumacode.com/
题意
给定两个整数 x与 y,你可以进行若干次操作,使得 x与 y相等。每次操作选择任意非负整数k,选择 x或 y 中的一个数,并将其值加上 2k。请计算使 x,y 相等所需的最少操作次数。
输入描述
每个测试文件均包含多组测试数据。第一行输入一个整数 T (1≤T≤10的4次方)代表数组组数,每组测试数据描述如下:
一行包含两个整数 x,y (−1018≤x,y≤1018),代表两个整数。
输出描述
对于每组测试数据,输出一行一个整数,表示使 x与 y相等的最少操作次数。
示例1
输入:
5
0 0
7 0
5 14
-3 5
-10 10
输出:
0
2
2
1
2
思路与代码我们可以将差值 d转化为二进制来看,从最低位开始处理(相当于每次除以 2):
如果当前 d 是偶数(最低位为 0):不需要任何操作,直接 d = d / 2即可。
如果当前 d是奇数(最低位为 1):我们必须进行一次操作,选择 +1 或 -1 让它变成偶数,然后继续除以 2。
什么时候该 +1? 如果 d 的二进制结尾是 11(即 d mod 4 = 3),加上 1 之后,会变成 100,不仅消除了当前位的 1,还触发了进位,把下一位的 1 也消灭了(一石二鸟)。
什么时候该 -1? 如果 d 的二进制结尾是 01(即 d mod 4 = 1$),减去 1 之后直接变成 00,是最划算的。
#include <iostream>
using namespace std;
void solve() {
long long x, y;
cin >> x >> y;
// 计算差值 d
// 题目数据范围是 -10^18 到 10^18,最大差值是 2 * 10^18
// 使用 unsigned long long 接收,防止任何潜在的符号干扰
unsigned long long d;
if (x > y) {
d = x - y;
} else {
d = y - x;
}
int ops = 0; // 记录操作次数
while (d > 0) {
// 判断当前最低位是否为 1 (即 d 是否为奇数)
if (d % 2 == 1) {
// 如果末尾两位是 11 (即 d % 4 == 3),加 1 触发进位最划算
if (d % 4 == 3) {
d++;
} else {
// 如果末尾两位是 01 (即 d % 4 == 1),减 1 最划算
d--;
}
ops++; // 进行了一次操作
}
// 处理完当前位,整体右移一位 (相当于除以 2)
d /= 2;
}
cout << ops << "\n";
}
int main() {
// 优化 C++ 的标准输入输出速度,防止被卡常数
ios_base::sync_with_stdio(false);
cin.tie(NULL);
int t;
if (cin >> t) {
while (t--) {
solve();
}
}
return 0;
}
我们是一个针对技术岗(前后端开发、测试、测开、大数据开发、大模型、ai等相关岗位)校招一对一进阶提高的工作室。我们从2020年2月份开始,迄今整整六年的时间,带领900+学员斩获4000+中大厂offer,参加活动的同学人均5个中大厂offer以上,以下是我们活动内容的介绍! 万诺coding
我们主要是针对有一定基础的同学提供全程一对一笔试、面试辅导,针对每个同学不同的情况定制内容,包括但不限于“笔试及面试算法”/“基础八股/“项目及实习梳理”/“面试技巧”/“面试复盘”等内容。
摸底测试:如果有兴趣深入了解我们的活动,需要先参加我们的“摸底测试”(类似面试),方便我们了解你的具体情况(主要是code能力和计算机素养),定制出相应的辅导计划。摸底测试后,我们会定制化一个针对性的提高计划。然后你再考虑是否参加我们的活动。
承诺保offer:通过摸底测试后,我们会针对每个同学的情况给定一个“保offer”计划。然后同学可以根据自己的实际情况考虑参不参加我们的活动。
有兴趣的同学可以扫码添加我们的微信(whynotlab)
