🍭 大家好这里是清隆学长 ,一枚热爱算法的程序员
✨ 本系列打算持续跟新 秋招笔试题
👏 感谢大家的订阅➕ 和 喜欢💗📧 清隆这边最近正在收集近一年半互联网笔试题汇总,有需要的小伙伴可以关注 文末 公主号领取~
文章目录
- 💡 本次的笔试难度跨度较大,前两题比较简单,最后一题需要 前缀和优化DP 解决,其中 `Python` 和 `Java` 在笔试中据说会超时
- 😒 01.心情管理大师
- 问题描述
- 输入格式
- 输出格式
- 样例输入
- 样例输出
- 数据范围
- 题解
- 参考代码
- 📝 02.密码学家的挑战
- 问题描述
- 输入格式
- 输出格式
- 样例输入
- 样例输出
- 样例说明
- 数据范围
- 题解
- 参考代码
- 🍿 03.魔法师的序列挑战
- 问题描述
- 输入格式
- 输出格式
- 样例输入1
- 样例输出1
- 样例输入2
- 样例输出2
- 数据范围
- 题解
- 参考代码
💡 本次的笔试难度跨度较大,前两题比较简单,最后一题需要 前缀和优化DP 解决,其中
Python
和Java
在笔试中据说会超时
😒 01.心情管理大师
问题描述
K小姐是一名心理咨询师,她最近在研究人们的心情变化规律。她发现,当一个人连续工作时,每天的心情指数会下降 A A A 点;而当这个人休息一天时,心情指数会上升1点。
K小姐想要帮助她的客户A先生进行心情管理。A先生目前的心情指数为0,他计划先连续工作 B B B 天,然后开始休假。K小姐想知道,从A先生开始工作到他的心情指数再次回到0,总共需要多少天。
请你帮助K小姐编写一个程序,计算出这个天数。
输入格式
第一行给出测试用例的数量 T T T。
随后 T T T 行,每行给出 A A A 和 B B B 的值,用空格分隔。
输出格式
输出 T T T 行,每行一个整数,表示对应测试用例的答案。
样例输入
2
2 3
3 1
样例输出
9
4
数据范围
1 ≤ T ≤ 100 1 \leq T \leq 100 1≤T≤100
1 ≤ A , B ≤ 1000 1 \leq A, B \leq 1000 1≤A,B≤1000
题解
-
计算 B B B 天工作后的心情指数变化: − A × B -A \times B −A×B。
-
计算需要多少天休息才能让心情指数回到0: A × B A \times B A×B。
-
3总天数就是工作天数加上休息天数: B + ( A × B ) = B × ( A + 1 ) B + (A \times B) = B \times (A + 1) B+(A×B)=B×(A+1)。
因此,我们可以直接用公式 B × ( A + 1 ) B \times (A + 1) B×(A+1) 计算出结果。
参考代码
- Python
def solve():# 读取输入的 a 和 b 值a, b = map(int, input().split())# 计算并输出结果print(b * (a + 1))# 读取测试用例数量
t = int(input())
# 循环处理每个测试用例
for _ in range(t):solve()
- Java
import java.util.Scanner;public class Main {public static void solve(Scanner sc) {// 读取输入的 a 和 b 值int a = sc.nextInt();int b = sc.nextInt();// 计算并输出结果System.out.println(b * (a + 1));}public static void main(String[] args) {Scanner sc = new Scanner(System.in);// 读取测试用例数量int t = sc.nextInt();// 循环处理每个测试用例while (t-- > 0) {solve(sc);}sc.close();}
}
- Cpp
#include <iostream>
using namespace std;void solve() {int a, b;// 读取输入的 a 和 b 值cin >> a >> b;// 计算并输出结果cout << b * (a + 1) << endl;
}int main() {int t;// 读取测试用例数量cin >> t;// 循环处理每个测试用例while (t--) {solve();}return 0;
}
📝 02.密码学家的挑战
问题描述
K小姐是一位密码学家,她最近在研究一种特殊的加密方法。这种方法将一个十进制数转换为不同进制(2 到 36 进制)的表示,其中 A 表示 10,B 表示 11,以此类推,Z 表示 35。
K小姐发现,某些数字在特定进制下的表示中只包含一个数字 1。她想知道,对于给定的十进制数 n n n,在所有 2 到 36 进制的表示中,最多可以包含多少个数字 1。
请你帮助 K小姐编写一个程序,计算出这个最大值。
输入格式
输入一行,包含一个整数 n n n( 1 ≤ n ≤ 3 ⋅ 1 0 5 1 \leq n \leq 3 \cdot 10^5 1≤n≤3⋅105),表示给定的十进制数。
输出格式
输出一行,包含一个整数,表示在 2 到 36 进制的所有表示中,数字 1 出现次数的最大值。
样例输入
4
样例输出
2
样例说明
当 n = 4 n=4 n=4 时,在 3 进制下表示为 ( 11 ) 3 (11)_3 (11)3,包含两个 1,这是最多的情况。
数据范围
1 ≤ n ≤ 3 ⋅ 1 0 5 1 \leq n \leq 3 \cdot 10^5 1≤n≤3⋅105
题解
-
对于给定的十进制数 n n n,遍历 2 到 36 的所有进制。
-
对于每种进制,将 n n n 转换为该进制的表示,并统计其中 1 的个数。
-
记录所有进制中 1 的个数的最大值。
关键在于如何高效地进行进制转换和计数。可以使用除法和取模运算来实现进制转换,同时统计 1 的出现次数。
时间复杂度分析:对于每个数 n n n,需要尝试 35 种进制(2 到 36),每次转换的时间复杂度为 O ( log n ) O(\log n) O(logn)。因此总的时间复杂度为 O ( 35 log n ) O(35 \log n) O(35logn)
参考代码
- Python
def solve():# 读取输入的十进制数n = int(input())# 初始化最大1的个数为0max_ones = 0# 遍历2到36的所有进制for base in range(2, 37):num, ones = n, 0# 进行进制转换,同时统计1的个数while num:if num % base == 1:ones += 1num //= base# 更新最大1的个数max_ones = max(max_ones, ones)# 输出结果print(max_ones)# 调用主函数
solve()
- Java
import java.util.Scanner;public class Main {public static void main(String[] args) {Scanner sc = new Scanner(System.in);// 读取输入的十进制数int n = sc.nextInt();// 初始化最大1的个数为0int maxOnes = 0;// 遍历2到36的所有进制for (int base = 2; base <= 36; base++) {int num = n, ones = 0;// 进行进制转换,同时统计1的个数while (num > 0) {if (num % base == 1) {ones++;}num /= base;}// 更新最大1的个数maxOnes = Math.max(maxOnes, ones);}// 输出结果System.out.println(maxOnes);sc.close();}
}
- Cpp
#include <iostream>
#include <algorithm>
using namespace std;int main() {int n;// 读取输入的十进制数cin >> n;// 初始化最大1的个数为0int maxOnes = 0;// 遍历2到36的所有进制for (int base = 2; base <= 36; base++) {int num = n, ones = 0;// 进行进制转换,同时统计1的个数while (num) {if (num % base == 1) {ones++;}num /= base;}// 更新最大1的个数maxOnes = max(maxOnes, ones);}// 输出结果cout << maxOnes << endl;return 0;
}
🍿 03.魔法师的序列挑战
问题描述
K小姐是一位魔法师,她最近在研究一种特殊的魔法序列。这种序列具有以下特性:
- 序列长度为 n n n,每个元素不超过 m m m。
- 序列是非递减的。
- 序列中所有元素的魔法异或值恰好等于 m m m。
K小姐想知道有多少种不同的魔法序列满足这些条件。你能帮助她解决这个难题吗?
输入格式
输入一行,包含两个整数 n n n 和 m m m( 1 ≤ n ≤ 300 1 \leq n \leq 300 1≤n≤300; 0 ≤ m ≤ 300 0 \leq m \leq 300 0≤m≤300),分别表示序列的长度和魔法异或值。
输出格式
输出一个整数,表示满足条件的魔法序列的数量。由于答案可能很大,请对 1 0 9 + 7 10^9 + 7 109+7 取模后输出。
样例输入1
3 2
样例输出1
4
样例输入2
200 200
样例输出2
391022064
数据范围
- 1 ≤ n ≤ 300 1 \leq n \leq 300 1≤n≤300
- 0 ≤ m ≤ 300 0 \leq m \leq 300 0≤m≤300
题解
这个问题可以使用动态规划来解决。定义状态 d p [ i ] [ j ] [ k ] dp[i][j][k] dp[i][j][k] 表示长度为 i i i,最后一个数是 j j j,异或和为 k k k 的方案数。
状态转移方程为:
d p [ i ] [ j ] [ k ] = ∑ 0 ≤ l ≤ j d p [ i − 1 ] [ l ] [ k ⊕ j ] dp[i][j][k] = \sum_{0 \leq l \leq j} dp[i-1][l][k \oplus j] dp[i][j][k]=∑0≤l≤jdp[i−1][l][k⊕j]
其中 ⊕ \oplus ⊕ 表示异或操作。
为了优化时间复杂度,可以使用前缀和来加速计算。最终的时间复杂度为 O ( n ⋅ m 2 ) O(n \cdot m^2) O(n⋅m2)。
据考友反馈,在笔试的时候python
和 java
代码是会超时的,建议冲 cpp
参考代码
- Python
MOD = 10**9 + 7def solve():n, m = map(int, input().split())# 初始化DP数组dp = [[[0] * (2*m+1) for _ in range(m+1)] for _ in range(n+1)]# 初始化长度为1的情况for j in range(m+1):dp[1][j][j] = 1# 动态规划过程for i in range(2, n+1):# 计算前缀和prefix_sum = [[0] * (2*m+1) for _ in range(m+1)]for j in range(m+1):for k in range(2*m+1):prefix_sum[j][k] = dp[i-1][j][k]if j > 0:prefix_sum[j][k] = (prefix_sum[j][k] + prefix_sum[j-1][k]) % MOD# 状态转移for j in range(m+1):for k in range(2*m+1):if k ^ j <= 2*m:dp[i][j][k] = prefix_sum[j][k ^ j]# 计算最终结果ans = sum(dp[n][j][m] for j in range(m+1)) % MODprint(ans)solve()
- Java
import java.util.Scanner;public class Main {static final int MOD = 1000000007;static final int N = 301;static int[][][] dp = new int[N][N][N << 1];static int[][] prefixSum = new int[N][N << 1];public static void main(String[] args) {Scanner sc = new Scanner(System.in);int n = sc.nextInt();int m = sc.nextInt();// 初始化长度为1的情况for (int j = 0; j <= m; j++) {dp[1][j][j] = 1;}// 动态规划过程for (int i = 2; i <= n; i++) {// 计算前缀和for (int j = 0; j <= m; j++) {for (int k = 0; k <= m * 2; k++) {prefixSum[j][k] = dp[i - 1][j][k];if (j > 0) {prefixSum[j][k] = (prefixSum[j][k] + prefixSum[j - 1][k]) % MOD;}}}// 状态转移for (int j = 0; j <= m; j++) {for (int k = 0; k <= 2 * m && (k ^ j) <= 2 * m; k++) {dp[i][j][k] = prefixSum[j][k ^ j];}}}// 计算最终结果int ans = 0;for (int j = 0; j <= m; j++) {ans = (ans + dp[n][j][m]) % MOD;}System.out.println(ans);}
}
- Cpp
#include <iostream>
#include <vector>
using namespace std;const int MOD = 1e9 + 7;
const int N = 301;int dp[N][N][N << 1]; // DP数组,dp[i][j][k]表示长度为i,最后一个数是j,异或和为k的方案数
int prefix_sum[N][N << 1]; // 前缀和数组,用于优化计算int main() {int n, m;cin >> n >> m;// 初始化长度为1的情况for (int j = 0; j <= m; ++j) {dp[1][j][j] = 1;}// 动态规划过程for (int i = 2; i <= n; i++) {// 计算前缀和for (int j = 0; j <= m; j++) {for (int k = 0; k <= m * 2; k++) {prefix_sum[j][k] = dp[i - 1][j][k];if (j > 0) {prefix_sum[j][k] = (prefix_sum[j][k] + prefix_sum[j - 1][k]) % MOD;}}}// 状态转移for (int j = 0; j <= m; j++) {for (int k = 0; k <= 2 * m && (k ^ j) <= 2 * m; k++) {dp[i][j][k] = prefix_sum[j][k ^ j];}}}// 计算最终结果int ans = 0;for (int j = 0; j <= m; ++j) {ans = (ans + dp[n][j][m]) % MOD;}cout << ans << "\n";return 0;
}