顺丰笔试 顺丰
笔试时间:2025年9月21日
往年笔试合集:
第一题:序列的构成方案数
现在有一个长度为 n 的整数序列,其中每个数字范围在 1 到 m 之间。序列中除第一个数字外,其他位置上的数字需要满足下列条件之一:
- 和前一个数字相差不超过 k
- 或者是前一个数字的整数倍
现在问这个序列有几种构成方案。答案对 10^9+7 取模。
输入描述
一行三个正整数 n, m, k,以空格分开,分别表示序列的长度为 n;序列中每个数字的范围在 1 到 m 之间;数字间相差的阈值 k。
输出描述
一个正整数,表示答案。
样例输入
3 2 1
样例输出
8
样例说明 共8种:[1,1,1], [1,1,2], [1,2,1], [1,2,2], [2,1,1], [2,1,2], [2,2,1], [2,3,3]
参考题解
解题思路:
- 状态定义:定义 dp[i][j] 表示长度为 i 且最后一个数字是 j 的合法序列有多少种。使用滚动数组优化空间。
- 状态转移:计算新一层的结果 nextDp[j] 时,需要考虑所有可以构成合法序列的前一个数字 p: 条件一:数字之差不超过 k,即 |j - p| <= k条件二:j 是 p 的整数倍
- 计算优化: 对于条件一,使用前缀和数组进行优化,可以在 O(1) 时间内求出区间和对于条件二,通过遍历到 sqrt(j) 来高效地找出所有约数
- 去重处理:先通过前缀和计算满足条件一的方案总数,然后在遍历约数时,只加上不满足条件一的方案数
- 最终结果:循环 n-1 次后,将 dp 数组中所有位置的值累加起来
C++:
#include <iostream> #include <vector> #include <cmath> #include <algorithm> using namespace std; int main() { int sequenceLength, numberRange, maxDifference; cin >> sequenceLength >> numberRange >> maxDifference; long long MODULO = 1000000007; vector<long long> prevSolutions(numberRange + 1, 1); prevSolutions[0] = 0; for (int len = 2; len <= sequenceLength; len++) { vector<long long> currentSolutions(numberRange + 1, 0); vector<long long> cumulativeSums(numberRange + 1, 0); for (int val = 1; val <= numberRange; val++) { cumulativeSums[val] = (cumulativeSums[val - 1] + prevSolutions[val]) % MODULO; } for (int val = 1; val <= numberRange; val++) { int left = max(1, val - maxDifference); int right = min(numberRange, val + maxDifference); long long sumFromDiff = (cumulativeSums[right] - cumulativeSums[left - 1] + MODULO) % MODULO; currentSolutions[val] = sumFromDiff; for (int div = 1; div * div <= val; div++) { if (val % div == 0) { int factorA = div; int factorB = val / div; if (factorA <= numberRange) { if (abs(val - factorA) > maxDifference) { currentSolutions[val] = (currentSolutions[val] + prevSolutions[factorA]) % MODULO; } } if (factorA != factorB && factorB <= numberRange) { if (abs(val - factorB) > maxDifference) { currentSolutions[val] = (currentSolutions[val] + prevSolutions[factorB]) % MODULO; } } } } } prevSolutions = currentSolutions; } long long totalCount = 0; for (int val = 1; val <= numberRange; val++) { totalCount = (totalCount + prevSolutions[val]) % MODULO; } cout << totalCount << 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 sequenceLength = scanner.nextInt(); int numberRange = scanner.nextInt(); int maxDifference = scanner.nextInt(); scanner.close(); long MODULO = 1_000_000_007; long[] prevSolutions = new long[numberRange + 1]; Arrays.fill(prevSolutions, 1); prevSolutions[0] = 0; for (int len = 2; len <= sequenceLength; len++) { long[] currentSolutions = new long[numberRange + 1]; long[] cumulativeSums = new long[numberRange + 1]; for (int val = 1; val <= numberRange; val++) { cumulativeSums[val] = (cumulativeSums[val - 1] + prevSolutions[val]) % MODULO; } for (int val = 1; val <= numberRange; val++) { int left = Math.max(1, val - maxDifference); int right = Math.min(numberRange, val + maxDifference); long sumFromDiff = (cumulativeSums[right] - cumulativeSums[left - 1] + MODULO) % MODULO; currentSolutions[val] = sumFromDiff; for (int div = 1; div * div <= val; div++) { if (val % div == 0) { int factorA = div; int factorB = val / div; if (factorA <= numberRange) { if (Math.abs(val - factorA) > maxDifference) { currentSolutions[val] = (currentSolutions[val] + prevSolutions[factorA]) % MODULO; } } if (factorA != factorB && factorB <= numberRange) { if (Math.abs(val - factorB) > maxDifference) { currentSolutions[val] = (currentSolutions[val] + prevSolutions[factorB]) % MODULO; } } } } } prevSolutions = currentSolutions; }
剩余60%内容,订阅专栏后可继续查看/也可单篇购买
2025 春招笔试合集 文章被收录于专栏
2025打怪升级记录,大厂笔试合集 C++, Java, Python等多种语言做法集合指南