携程笔试 携程笔试题 20260312

笔试时间:2026年3月12日

往年笔试合集:

2023春招秋招笔试合集

2024春招秋招笔试合集

第一题:尾巴大人

难度:简单(签到题)

题目描述

众所周知 ! 很像一个尾巴,表示 n 的阶乘即 n!。给定一个整数 n,游游想知道 n! 的个位数字是多少,请输出这个值。

输入描述

输入一行一个整数 n 表示询问值。

输出描述

输出一个整数表示 n! 的个位数字。

样例输入1

1

样例输出1

1

样例输入2

7

样例输出2

0

样例说明

7! = 5040,个位是 0。

参考题解

解题思路:

这道题的核心思路基于阶乘的数学性质:当 n >= 5 时,阶乘的展开式中必然同时包含因子 2 和 5。因为 2 × 5 = 10,这意味着任何大于等于5的整数阶乘,其计算结果的末尾至少会带有一个 0,因此它的个位数字永远是 0。

对于 n < 5 的情况,由于计算量极小,直接采用穷举的方式硬编码结果:1! = 1,2! = 2,3! = 6,4! = 24(个位取4)。

Java:

import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        if (scanner.hasNextLong()) {
            long n = scanner.nextLong();
            if (n >= 5) {
                System.out.println(0);
            } else if (n == 4) {
                System.out.println(4);
            } else if (n == 3) {
                System.out.println(6);
            } else if (n == 2) {
                System.out.println(2);
            } else if (n == 1) {
                System.out.println(1);
            }
        }
    }
}

C++:

#include <iostream>
using namespace std;

int main() {
    long long n;
    cin >> n;
    if (n >= 5) {
        cout << 0 << endl;
    } else if (n == 4) {
        cout << 4 << endl;
    } else if (n == 3) {
        cout << 6 << endl;
    } else if (n == 2) {
        cout << 2 << endl;
    } else if (n == 1) {
        cout << 1 << endl;
    }
    return 0;
}

Python:

n = int(input())
if n >= 5:
    print(0)
elif n == 4:
    print(4)
elif n == 3:
    print(6)
elif n == 2:
    print(2)
elif n == 1:
    print(1)

第二题:拆盲盒

难度:中等

题目描述

给定一个正整数 n 与一个正整数 m。你需要把 n 拆分为若干个素数之和(可以重复选择同一个素数),设最终使用的素数个数为 k。同时要求:所选素数中奇素数(除 2 以外的素数)的数量必须是 m 的正整数倍(不能为 0)。请在满足约束的前提下,使 k 最大化,并输出这个最大的 k。若不存在任何满足要求的拆分方案,输出 -1。

【名词解释】

素数:大于 1 且只有 1 与其本身两个正因子的整数;

奇素数:除 2 以外的素数。

输入描述

每个测试文件均包含多组测试数据。第一行输入一个整数 T(1 ≤ T ≤ 10^5)表示测试数据组数,每组测试数据描述如下:在一行上输入两个整数 n, m(1 ≤ n ≤ 10^12, 1 ≤ m ≤ 10^9)。

输出描述

对于每一组测试数据,新起一行输出一个整数:满足要求的最大的素数个数 k;若无解,则输出 -1。

样例输入

4
6 2
2 1
30 4
1000000000000 1

样例输出

2
-1
13
499999999999

样例说明

对于第一组样例 6 可以拆分为 3 + 3。

参考题解

解题思路:

涉及算法:贪心算法 + 奇偶性分析。

为了使拆分出的素数总个数最大化,我们需要尽可能多地使用数值最小的素数,即偶素数 2 和奇素数 3。为了把更多的数值份额留给消耗仅为 2 的偶素数,我们应该使用刚好满足条件的最少数量的奇素数(即全选 3),并确保减去这些 3 之后,剩下的数值是一个非负偶数,以便能被 2 完全整除。

具体逻辑通过奇偶性来判断:如果总和 n 与要求的奇素数基数 m 奇偶性相同,那么选 m 个奇素数刚好能让剩余值为偶数;如果 n 是偶数而 m 是奇数,选 m 个奇素数会导致剩余值为奇数(无法全用 2 凑齐),所以必须将奇素数的要求数量翻倍到 2m;如果 n 是奇数而 m 是偶数,因为偶数个奇数相加永远是偶数,再加上若干个 2 永远凑不出奇数的 n,这种天然的奇偶冲突会导致绝对无解(输出 -1)。最后,只需判断总和 n 是否足够容纳最少数量的 3(即 minOddSum <= n / 3),如果满足,则直接用公式算出最大个数。

Java:

import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        if (!in.hasNextInt()) return;
        int testCases = in.nextInt();
        while (testCases-- > 0) {
            long totalSum = in.nextLong();
            long reqOddCount = in.nextLong();
            long minOddSum = -1;
            if (totalSum % 2 == reqOddCount % 2) {
                minOddSum = reqOddCount;
            } else if (totalSum % 2 == 0 && reqOddCount % 2 != 0) {
                minOddSum = 2 * reqOddCount;
            }
            if (minOddSum != -1 && minOddSum <= totalSum / 3) {
                System.out.println((totalSum - minOddSum) / 2);
            } else {
                System.out.println("-1");
            }
        }
    }
}

C++:

#include <iostream>
using namespace std;

int main() {
    int testCases;
    cin >> testCases;
    while (testCases-- > 0) {
        long long totalSum, reqOddCount;
        cin >> totalSum >> reqOddCount;
        long long minOddSum = -1;
        if (totalSum % 2 == reqOddCount % 2) {
            minOddSum = reqOddCount;
        } else if (totalSum % 2 == 0 && reqOddCount % 2 != 0) {
            minOddSum = 2 * reqOddCount;
        }
        if (minOddSum != -1 && minOddSum <= totalSum / 3) {
            cout << (totalSum - minOddSum) / 2 << "\n";
        } else {
            cout << -1 << "\n";
        }
    }
    return 0;
}

Python:

import sys
input = sys.stdin.readline

test_cases = int(input())
for _ in range(test_cases):
    total_sum, req_odd_count = map(int, input().split())
    min_odd_sum = -1
    if total_sum % 2 == req_odd_count % 2:
        min_odd_sum = req_odd_count
    elif total_sum % 2 == 0 and req_odd_count % 2 != 0:
        min_odd_sum = 2 * req_odd_count
    if min_odd_sum != -1 and min_odd_sum <= total_sum // 3:
        print((total_sum - min_odd_sum) // 2)
    else:
        print(-1)

第三题:天才的数列切割

难度:较高

题目描述

给定一个长度为 n 的数组 a₁, a₂, ..., aₙ。你将对数组进行若干次"切割"操作,操作规则如下:

一开始,数组段集合仅包含整段 [1, n];

每次操作,必须从"当前数组段集合"中选择一段完整的数组段 [l, r](该段长度需严格大于 2),然后选择一个位置 mid(l ≤ mid < r),若满足:

sum(a[l..mid]) = sum(a[mid+1..r])

则可以把该数组段分成两段 [l, mid] 与 [mid+1, r],并以这两段替换原来的 [l, r],继续加入到数组段集合中;

一旦一个数组段被切割,它将从集合中移除并被两个新的子段取代。你只能选择当前集合中存在的完整段进行下一次切割,不允许跨越段边界或在段内截取任意子段进行操作。

所有区间均以原数组的下标表示,不进行重新编号;切割后得到的两个区间互不重叠,且并集为原区间。请你计算,在最优策略下,总共最多能进行多少次切割。

输入描述

第一行输入一个整数 n(1 ≤ n ≤ 10^5)表示数组的长度;第二行输入 n 个整数 a₁, a₂, ..., aₙ 表示数组中的元素。

输出描述

输出一个整数,表示最多的切割次数,若不存在任何合法的切割方案,输出 0。

样例输入

6
1 2 1 1 1 2

样例输出

2

样例说明

对全段 [1,6],可在 mid=3 处切割,因为 sum(a[1..3]) = sum(a[4..6]) = 4,得到 [1,3] 与 [4,6]。随后 [4,6] 在 mid=5 处再次切割,因为 sum(a[4..5]) = sum(a[6..6]) = 2。总共进行了 2 次切割。

参考题解

解题思路:

涉及算法:前缀和 + 二分查找 + 分治递归。

首先,代码在读取数据时预处理出了整个数组的前缀和,这样做的目的是为了在后续递归过程中,能够以 O(1) 的时间复杂度快速计算出任意子区间的元素总和。

在递归处理每次的区间 [left, right] 时,首先判断区间长度是否严格大于 2 且区间总和是否为偶数(奇数无法被平分成两个整数和),若不满足则说明无法继续切割,直接返回 0。若满足条件,则计算出将该区间平分所需达到的"目标前缀和",并利用二分查找快速定位合法的切割位置;如果找到了该切割点,就将本次操作计为 1 次切割,并累加上对切开的左右两个新子区间继续递归求解出的切割次数。

Java:

import java.io.InputStream;
import java.util.Arrays;

public class Main {
    static long[] preSums;

    public static void main(String[] args) throws Exception {
        InputStream stream = System.in;
        int ch = stream.read();
        while (ch <= 32) {
            if (ch == -1) return;
            ch = stream.read();
        }
        int len = 0;
        while (ch > 32) {
            len = len * 10 + (ch - '0');
            ch = stream.read();
        }
        preSums = new long[len + 1];
        for (int i = 1; i <= len; i++) {
            ch = stream.read();
            while (ch <= 32) {
                if (ch == -1) break;
                ch = stream.read();
         

剩余60%内容,订阅专栏后可继续查看/也可单篇购买

2025 春招笔试合集 文章被收录于专栏

2025打怪升级记录,大厂笔试合集 C++, Java, Python等多种语言做法集合指南

全部评论

相关推荐

评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务