2024年3月31日微众银行春招实习试题-题目+题解+在线评测【3题 模拟 二分 动态规划】
题目一描述:输入格式输出格式样例输入样例输出评测数据与规模解题思路一:模拟,切片操作解题思路二:for循环
题目二描述:输入格式输出格式样例输入样例输出评测数据与规模
解题思路一:二分查找,小于当前预算的城市的旅行花费bisect.bisect_right(costs, v)解题思路一:手撕二分查找
题目三描述:输入格式输出格式样例输入样例输出评测数据与规模
解题思路一:
题号题目提交网址难度(对标leetcode)核心做法01魔法迷宫简单模拟02塔子哥的春季旅行计划中等二分03塔子哥的魔法宝石中等动态规划
题目一描述:
塔子哥在玩一款魔法迷宫游戏。迷宫由一个 3×3 的网格组成,每个格子中有一个魔法物品。塔子哥每次可以选择一行或一列,并将其向左、右、上、下滑动一格。滑出边界的物品会从另一端出现。例如,如果将第一行 123 向左滑动一格,它将变成 231。
游戏开始时,魔法物品的初始状态如下:
1 2 3
4 5 6
7 8 9
塔子哥想知道,经过若干次操作后,迷宫中魔法物品的排列会变成什么样。
输入格式
第一行包含一个正整数 n,表示操作的数量。
第二行包含 n 个正整数,其中第 i 个数表示第 i 次操作:
如果操作为 1、2、3,分别表示将第 1、2、3 行向右滑动一格。如果操作为 4、5、6,分别表示将第 1、2、3 列向上滑动一格。
输出格式
输出 3 行,每行 3 个数,表示经过所有操作后迷宫的状态。
样例输入
2
1 5
样例输出
3 5 2
4 8 6
7 1 9
评测数据与规模
1≤n≤500001, 1≤op≤61 。
解题思路一:模拟,切片操作
按题意模拟即可,使用一个二维数组来表示迷宫的状态,然后根据输入的操作依次对数组进行修改。
对于向右滑动一行的操作,先保存该行最右边的元素,然后从右到左依次将每个元素替换为其左边的元素,最后将最左边的元素替换为之前保存的最右边的元素。
对于向上滑动一列的操作,先保存该列最上面的元素,然后从上到下依次将每个元素替换为其下面的元素,最后将最下面的元素替换为之前保存的最上面的元素。
n = int(input())
ops = list(map(int, input().split()))
matrix = [[1,2,3], [4,5,6], [7,8,9]]
for op in ops:
if op <=3:
row = matrix[op - 1]
tmp = row[-1]
row[-2:] = row[:2]
row[0] = tmp
matrix[op-1] = row
else:
tmp = matrix[0][op-4]
for j in range(1, 3):
matrix[j-1][op-4] = matrix[j][op-4]
matrix[2][op-4] = tmp
for row in matrix:
for item in row:
print(item, end = ' ')
print()
时间复杂度:O(n) 空间复杂度:O(1)
解题思路二:for循环
n = int(input())
matx = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
a = list(map(int, input().split()))
for op in a:
if op <= 3:
t = matx[op - 1][2]
for j in range(2, 0, -1):
matx[op - 1][j] = matx[op - 1][j - 1]
matx[op - 1][0] = t
else:
t = matx[0][op - 4]
for j in range(2):
matx[j][op - 4] = matx[j + 1][op - 4]
matx[2][op - 4] = t
for row in matx:
for elem in row:
print(elem, end=" ")
print()
时间复杂度:O(n) 空间复杂度:O(1)
题目二描述:
春天到了,塔子哥计划去 n 个不同的城市旅行。每个城市都有各自的旅行花费,分别为 x1,x2,⋯ ,xn。塔子哥列出了 m 个预算方案,其中第 i 个方案的预算为 vi。现在,塔子哥想知道对于每个预算方案,他可以选择多少个不同的城市进行旅行。
输入格式
第一行包含一个正整数 n,表示城市的数量。
第二行包含 n 个正整数 x1,x2,⋯ ,xn,表示每个城市的旅行花费。
第三行包含一个正整数 m,表示预算方案的数量。
接下来 m 行,每行包含一个正整数 vi,表示第 i 个预算方案的预算金额。
输出格式
输出共 m 行,每行一个整数,表示对于每个预算方案,塔子哥可以选择的不同城市数量。
样例输入
5
3 10 8 6 11
4
1
10
3
11
样例输出
0
4
1
5
评测数据与规模
1≤n,m≤105,
1
≤
x
i
,
v
i
≤
1
0
9
1 \leq x_i, v_i \leq 10^9
1≤xi,vi≤109。
解题思路一:二分查找,小于当前预算的城市的旅行花费bisect.bisect_right(costs, v)
抽象完题意可以发现每组询问就是求数组 costs 中有多少个比 v 小的数。
这边只需要对 costs 数组排序后二分判断即可。
import bisect
n = int(input())
costs = list(map(int, input().split()))
costs.sort()
m = int(input())
for i in range(m):
v = int(input())
idx = bisect.bisect_right(costs, v)
print(idx)
# 同意
#include
using namespace std;
#define int long long
signed main (){
ios::sync_with_stdio(false);
std::cin.tie(0);
int n; cin >> n;
vector
for(int i = 0; i < n; i ++) cin >> a[i];
sort(a.begin(), a.end());
int m; cin >> m;
for(int i = 0; i < m; i ++)
{
int v; cin >> v;
int idx = upper_bound(a.begin(), a.end(), v) - a.begin();
cout << idx << "\n";
}
return 0;
}
时间复杂度:O(mlogn) 空间复杂度:O(1)
解题思路一:手撕二分查找
import bisect
n = int(input())
costs = list(map(int, input().split()))
costs.sort()
m = int(input())
# lower_bound 返回最小的满足 nums[i] >= target 的 i
# 如果数组为空,或者所有数都 < target,则返回 len(nums)
# 要求 nums 是非递减的,即 nums[i] <= nums[i + 1]
# 闭区间写法
def lower_bound(nums, target) -> int:
left, right = 0, len(nums) - 1 # 闭区间 [left, right]
while left <= right: # 区间不为空
# 循环不变量:
# nums[left-1] < target
# nums[right+1] >= target
mid = (left + right) // 2
if nums[mid] < target:
left = mid + 1 # 范围缩小到 [mid+1, right]
else:
right = mid - 1 # 范围缩小到 [left, mid-1]
return left # 或者 right+1
# 左闭右开区间写法
def lower_bound2(nums, target) -> int:
left = 0
right = len(nums) # 左闭右开区间 [left, right)
while left < right: # 区间不为空
# 循环不变量:
# nums[left-1] < target
# nums[right] >= target
mid = (left + right) // 2
if nums[mid] < target:
left = mid + 1 # 范围缩小到 [mid+1, right)
else:
right = mid # 范围缩小到 [left, mid)
return left # 或者 right
# 开区间写法
def lower_bound3(nums, target) -> int:
left, right = -1, len(nums) # 开区间 (left, right)
while left + 1 < right: # 区间不为空
mid = (left + right) // 2
# 循环不变量:
# nums[left] < target
# nums[right] >= target
if nums[mid] < target:
left = mid # 范围缩小到 (mid, right)
else:
right = mid # 范围缩小到 (left, mid)
return right # 或者 left+1
for i in range(m):
v = int(input())
idx = lower_bound(costs, v+1)
print(idx)
时间复杂度:O(mlogn) 空间复杂度:O(1)
题目三描述:
塔子哥和他的好朋友在玩一个魔法宝石的游戏。游戏开始时,有一颗魔法宝石,其能量值为 x。每回合,塔子哥可以给宝石注入能量值在[a, b] 之间的能量,而他的朋友可以注入能量值在 [c, d] 之间的能量。当宝石的能量值大于等于 s 时,游戏结束,最后一个操作宝石的人将获得胜利。
游戏中,塔子哥总是先手。双方都采取最优策略,你的任务是判断对于给定的初始能量值 x 和获胜能量值 s,谁能够获得最后的胜利。
输入格式
第一行包含一个正整数 T,表示询问的组数。
接下来 T 行,每行包含六个正整数 x,s,a,b,c,d,表示初始能量值、获胜能量值以及双方每回合能够注入的能量值范围。每个数字之间用一个空格隔开。
输出格式
对于每组询问,如果塔子哥获胜,输出 1,否则输出 2。每个答案占一行。
样例输入
3
1 10 1 1 2 2
1 4 1 2 1 2
1 2 1 3 1 3
样例输出
2
2
1
评测数据与规模
1≤T≤100 ,1≤x≤s≤1000 ,1≤a≤b≤100 ,1≤c≤d≤100 。
解题思路一:
在笔试中为数不多的博弈论的题,一般碰到这种类型的题一般有以下三种解法:
猜结论动态规划求 sg 函数
由于这题数据范围比较小,我们直接 DP 即可。
定义 dfs(x, f),表示当前宝石的能量值为 x,当前操作者是 f(塔子哥为 True,朋友为 False),返回在双方都采取最优策略的情况下,当前操作者是否能获胜。
如果当前操作者是塔子哥,那么他会尝试给宝石注入 a 到 b 之间的能量。如果注入后能量值大于等于 s,那么塔子哥直接获胜
否则,对于塔子哥注入的每一个可能的能量值,继续往下递归,如果有一种情况下朋友无法获胜,那么塔子哥获胜。
如果当前操作者是朋友,则同理,只是注入的能量值范围变成了 c 到 d。
def dfs(x, f):
if dp[x][f] != -1:
return dp[x][f]
if f:
if x + b >= s:
dp[x][f] = 1
return 1
for i in range(a, b + 1):
if dfs(x + i, not f):
dp[x][f] = 1
return 1
dp[x][f] = 0
return 0
else:
if x + d >= s:
dp[x][f] = 0
return 0
for i in range(c, d + 1):
if not dfs(x + i, not f):
dp[x][f] = 0
return 0
dp[x][f] = 1
return 1
t = int(input())
for _ in range(t):
x, s, a, b, c, d = map(int, input().split())
dp = [[-1] * 2 for _ in range(1005)]
ok = dfs(x, True)
print(1 if ok else 2)
时间复杂度:O(n2) 空间复杂度:O(n)
推荐链接
发表评论