美团笔试 美团笔试题 0510
笔试时间:2025年5月10日
往年笔试合集:
第一题:行走
小美正在一个无限大的二维坐标轴上运动,初始时她位于坐标(x,y)。她将基于一个由 n个整数组成的数组{a1,a2,...,an}进行移动,对于第i次移动,她都需要选择这样两个整数l和r,满足|l|+|r|= ai,随后移动到(x+l,y+r)这个位置。现在请问,n次移动后,她能否恰好移动到(p,q)这个位置。
输入描述
第-行一个整数t(1<=t<=1000)表示数据组数。对于每组数据格式为:
第一行一个整数 n(1<=n<=10^5),表示数组长度。
第二行n个整数,第i个整数为ai(0 ≤ ai<=1),表示每次移动的距离。
第三行四个整数x,y,p,q(-10^18≤ x,y,p,q ≤ 10^18),分别表示起点的横纵坐标,终点的横纵坐标。
数据保证单个测试文件∑n ≤10^5
输出描述
对于每组数据输出一个字符串,若可以恰好移动到(p,q)输出 "YES",否则输出"NO"。
样例输入
2
2
0 0
1 1 1 1
3
1 1 1
1 1 2 2
样例输出
YES
NO
参考题解
模拟,由于a[i]=1代表会在一个方向上走一步,因此只需要总步数和(x,y)(p,q)两个坐标差,相差的奇偶性相同即可,且需要保证总步数大于坐标差。
C++:
#include <iostream> #include <vector> #include <numeric> #include <cmath> using namespace std; int main() { int t; cin >> t; for (int i = 0; i < t; i++) { int n; cin >> n; vector<int> a(n); for (int j = 0; j < n; j++) { cin >> a[j]; } int x, y, p, q; cin >> x >> y >> p >> q; int dx = p - x; int dy = q - y; int s = accumulate(a.begin(), a.end(), 0); int sumAbs = abs(dx) + abs(dy); if (sumAbs > s) { cout << "NO" << endl; } else if (sumAbs % 2 != s % 2) { cout << "NO" << endl; } else { cout << "YES" << endl; } } return 0; }
Java:
import java.util.Scanner; import java.util.Arrays; public class Main { public static void main(String[] args) { Scanner scanner = new Scanner(System.in); int t = scanner.nextInt(); for (int i = 0; i < t; i++) { int n = scanner.nextInt(); int[] a = new int[n]; for (int j = 0; j < n; j++) { a[j] = scanner.nextInt(); } int x = scanner.nextInt(); int y = scanner.nextInt(); int p = scanner.nextInt(); int q = scanner.nextInt(); int dx = p - x; int dy = q - y; int s = 0; for (int num : a) { s += num; } int sumAbs = Math.abs(dx) + Math.abs(dy); if (sumAbs > s) { System.out.println("NO"); } else if (sumAbs % 2 != s % 2) { System.out.println("NO"); } else { System.out.println("YES"); } } scanner.close(); } }
Python:
t = int(input()) for _ in range(t): n = int(input()) a = list(map(int, input().split())) x, y, p, q = map(int, input().split()) dx = p - x dy = q - y s = sum(a) # 由于数组元素非0即1,s也是1的数量 sum_abs = abs(dx) + abs(dy) if sum_abs > s: print("NO") elif sum_abs % 2 != s % 2: print("NO") else: print("YES")
第二题:小美的数对合并
由于小美对图论十分感兴趣,因此小美希望创建一个属于自己的无向图。他有一个长度为n的数组a,他认为一对数字i,j是好的当且仅当:i,j(1<=i<j<=n)同时i-j<ai-aj。小美创建图的方式则是:对于任意一个点对 u,v(1≤u,v≤n),如果u,v是一对好的数字,则他会在u,v之间连上一条无向边。现在小美想知道,他所创建出的图有多少个极大连通块,由于图中的边数过多他数不过来,因此他想请你帮他算一算。对于图上的两个点,如果它们之间有边相连,则称他们位于同一个连通块里。对于一个连通块,如果其已经无法再加入更多的点,则称其为极大连通块。
输入描述
每个测试文件均包含多组测试数据。第一行输入一个整数T(1≤T≤100)代表数据组数,每组测试数据描述如下:
第一行输入一个整数n(1≤n≤2x10^5),表示数组a的长度。
第二行输入n个正整数 a1,a2,...,an(1≦ai≤10^9),表示数组。
除此之外,保证单个测试文件的 n 之和不超过2x10^5
输出描述
对于每组测试数据:
输出一行一个正整数表示他的图中连通块的个数。
样例输入
2
4
3 3 4 6
5
1 2 3 4 5
样例输出
2
5
参考题解
题意的约束可以转化为i<j,且i-a[i]<j-a[j],因此构建新数组ci=i-a[i]。假设把极大连通块的最大值定义为我们待统计的一个连通块的根,因此需要维护后缀最大值,对于答案统计,如果当前节点是后缀最大值且无法和前面的连通块合并,则ans++。对于和前面连通块合并,只需要考察当前a[i]是否比前面出现过的最小值要大即可。
C++:
#include<iostream> using namespace std; int t,n,a[200005], rmax[200005]; int main() { cin>>t; while(t--) { scanf("%d", &n); for(int i = 1; i<=n; i++) { cin>>a[i]; a[i] = i-a[i]; } rmax[n+1] = -1e9; for(int i = n; i>=1; i--) { rmax[i] = max(rmax[i+1], a[i]); } int ans = 0; int all_minn = 1e9+1, pre_minn = 1e9+1; for(int i = 1; i<=n; i++) { if(a[i] == rmax[i]) { if(a[i] <= pre_minn) { ans++; } pre_minn = min(pre_minn, all_minn); } all_minn = min(all_minn, a[i]); } cout << ans << endl; } return 0; }
Java:
import sys def main(): input = sys.stdin.read().split() ptr = 0 t = int(input[ptr]) ptr += 1 for _ in range(t): n = int(input[ptr]) ptr += 1 a = [0] * (n + 2) # 索引从1开始 rmax = [0] * (n + 2) for i in range(1, n+1): a[i] = int(input[ptr]) ptr += 1 a[i] = i - a[i] rmax[n+1] = -1e9 for i in range(n, 0, -1): rmax[i] = max(rmax[i+1], a[i]) ans = 0 all_minn = 1e9 + 1 pre_minn = 1e9 + 1
剩余60%内容,订阅专栏后可继续查看/也可单篇购买
2025打怪升级记录,大厂笔试合集 C++, Java, Python等多种语言做法集合指南