🍭 大家好这里是清隆学长 ,一枚热爱算法的程序员
✨ 本系列打算持续跟新 秋招笔试题
👏 感谢大家的订阅➕ 和 喜欢💗📧 清隆这边最近正在收集近一年半互联网笔试题汇总,有需要的小伙伴可以关注 文末 公主号领取~
文章目录
💡 本次的笔试难度跨度较大,前两题比较简单,最后一题需要 前缀和优化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的个数为0
max_ones = 0
# 遍历2到36的所有进制
for base in range(2, 37):
num, ones = n, 0
# 进行进制转换,同时统计1的个数
while num:
if num % base == 1:
ones += 1
num //= 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的个数为0
int 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的个数为0
int 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 + 7
def 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)) % MOD
print(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;
}