360笔试 360秋招 360笔试题 0920
笔试时间:2025年9月20日
往年笔试合集:
第一题:字符串操作
题目描述:给定长度为 n 的字符串 s1 和长度为 m 的字符串 s2。对于长度为 L 的字符串,它的子串 s[l,r](1≤l≤r≤L)是指从第 l 个字符开始到第 r 个字符结束这一段所构成的字符串。
请判断是否能够通过进行至多 1 次以下操作使得字符串 s1 和字符串 s2 完全相同:在字符串 s1 中选择一个子串 s1[l,r](1≤l≤r≤n),将该子串从 s1 中删除,同时将该子串添加到 s2 末尾。
输入描述
输入包含多组测试数据。输入第一行包含一个整数 T(1≤T≤100),表示数据组数。之后每三行描述一组测试数据:
- 第一行包含两个正整数 n 和 m(1≤m≤n≤100)分别表示字符串 s1 和 s2 的长度。
- 第二行包含一个长度为 n 的字符串,表示字符串 s1,保证仅包含小写英文字母。
- 第三行包含一个长度为 m 的字符串,表示字符串 s2,保证仅包含小写英文字母。
输出描述
对于每组测试数据输出一行,如果能够通过至多 1 次操作使得字符串 s1 和 s2 完全相同,则输出 YES,否则输出 NO。
样例输入
2
4 2
acdc
ad
4 2
accd
ad
样例输出
YES
NO
样例说明: 对于样例的第一组测试数据,可以从 s1 中选择子串 "cd",操作后有 s1="ad", s2="adcd"。 对于样例的第二组测试数据,通过该操作无法使得 s1 和 s2 完全相同。
参考题解
解题思路:
- 操作后 s1 和 s2 必须相同:设操作中删除的子串长度为 k,那么操作后新的 s1 长度为 n-k,新的 s2 长度为 m+k。要求两者相等:n-k = m+k,解得 k = (n-m)/2。因此,n-m 必须是偶数。
- 如果 k=0(即 n=m),则不需要操作,直接判断 s1 和 s2 是否相等。
- 否则,枚举所有可能的子串起始位置,检查移除该子串后的 s1 是否等于 s2 拼接上该子串。
C++:
#include <iostream> #include <string> using namespace std; int main() { int T; cin >> T; while (T--) { int n, m; cin >> n >> m; string s1, s2; cin >> s1 >> s2; if ((n - m) % 2 != 0) { cout << "NO" << endl; continue; } int k = (n - m) / 2; if (k == 0) { cout << (s1 == s2 ? "YES" : "NO") << endl; continue; } bool found = false; for (int start = 0; start <= n - k; start++) { string segment = s1.substr(start, k); string remaining = s1.substr(0, start) + s1.substr(start + k); if (remaining == s2 + segment) { found = true; break; } } cout << (found ? "YES" : "NO") << endl; } return 0; }
Java:
import java.util.*; public class Solution { public static void main(String[] args) { Scanner scanner = new Scanner(System.in); int T = scanner.nextInt(); while (T-- > 0) { int n = scanner.nextInt(); int m = scanner.nextInt(); String s1 = scanner.next(); String s2 = scanner.next(); if ((n - m) % 2 != 0) { System.out.println("NO"); continue; } int k = (n - m) / 2; if (k == 0) { System.out.println(s1.equals(s2) ? "YES" : "NO"); continue; } boolean found = false; for (int start = 0; start <= n - k; start++) { String segment = s1.substring(start, start + k); String remaining = s1.substring(0, start) + s1.substring(start + k); if (remaining.equals(s2 + segment)) { found = true; break; } } System.out.println(found ? "YES" : "NO"); } scanner.close(); } }
Python:
import sys def main(): I = sys.stdin.readline T = int(I()) for _ in range(T): n, m = map(int, I().split()) s1 = I().strip() s2 = I().strip() if (n - m) % 2 != 0: print("NO") continue k_val = (n - m) // 2 if k_val == 0: print("YES" if s1 == s2 else "NO") continue found = False for start in range(n - k_val + 1): segment = s1[start:start + k_val] remaining = s1[:start] + s1[start + k_val:] if remaining == s2 + segment: found = True break print("YES" if found else "NO") if __name__ == "__main__": main()
第二题:激光射击
题目描述:小明在玩一款叫做激光射击的游戏。
游戏在一个平面直角坐标系上进行。游戏的场地为一个 n×m 的矩形区域,其中矩形的四个顶点分别为 (0,0)、(n,0)、(n,m)、(0,m)。一束激光装置放置在 (0,0) 的位置,玩家可以向区域内任意方向发射一束激光。激光会沿着直线行进,当其抵达矩形区域的某个边界时,它会从跟该边界平行的另一个边界射出,方向不变。具体的,当激光抵达边界 x=n(0≤y≤m)时,激光会从 x=0 射出;当激光抵达边界 y=m(0≤x≤n)时,激光会从 y=0 射出;然而在 x=0 处有一个吸收装置,当激光抵达边界 x=0 时,激光会被吸收。
区域内有若干个靶,每个靶都可以看作一个点,并且其坐标均为整数。当激光击中靶子时,靶子会消失,同时玩家得一分。
小明希望自己的得分最大。请计算小明可以获得的最大得分是多少。
输入描述
第一行三个整数 n、m、k(1≤n,m≤10^6,0≤k≤500),表示矩形区域的大小以及靶子的数量。
接下来 k 行,每行两个整数 x_i, y_i(0<x_i<n,0<y_i<m),表示靶子的坐标。保证所有靶子的坐标都不相同。
输出描述
一个整数,表示小明可以获得的最大得分。
样例输入
5 5 7
1 3
1 4
2 1
2 2
3 3
3 4
4 2
样例输出
4
样例说明: 向 (1,1) 方向发射激光,击中的靶子的数量最多,得分最大为 4。
参考题解
解题思路:
- 激光路径的周期性:由于反射规则,激光路径在平面上会周期性重复。可以将整个平面"展开",将反射视为进入了一个镜像世界。
- 方向向量的简化:对于每个靶子,考虑它在四个象限的镜像位置,这些点与原点连线的方向向量可以代表激光可能的方向。方向向量需要化简为最简分数形式。
- 直线方程与整数解:对于每个方向向量,检查每个靶子是否位于该方向的激光路径上,这转化为求解线性丢番图方程。
- 使用扩展欧几里得算法求解方程,判断是否存在整数解。
- 对每个方向向量,计算能击中的靶子数量,取最大值。
C++:
#include <iostream> #include <vector> #include <set> #include <algorithm> #include <numeric> #include <cmath> using namespace std; int gcd(int a, int b) { return __gcd(abs(a), abs(b)); } tuple<int, long long, long long> extended_gcd(long long a, long long b) { if (a == 0) return {b, 0, 1}; auto [d, x1, y1] = extended_gcd(b % a, a); long long x = y1 - (b / a) * x1; long long y = x1; return {d, x, y}; } int main() { int n, m, k; cin >> n >> m >> k; vector<pair<int, int>> targets(k); for (int i = 0; i < k; i++) { cin >> targets[i].first >> targets[i].second; } int max_score = k > 0 ? 1 : 0; set<pair<int, int>> directions; for (auto& [x, y] : targets) { for (int a_wrap = 0; a_wrap <= 1; a_wrap++) { for (int b_wrap = 0; b_wrap <= 1; b_wrap++) { int nx = x + a_wrap * n; int ny = y + b_wrap * m; if (nx == 0 && ny == 0) continue; int g = gcd(nx, ny); directions.insert({nx / g, ny / g});
剩余60%内容,订阅专栏后可继续查看/也可单篇购买
2025打怪升级记录,大厂笔试合集 C++, Java, Python等多种语言做法集合指南