507周赛-①贪心②前缀和+暴力枚举/前缀和+三指针滑动窗口③分层图最短路④二分答案

1487 字
7 分钟
507周赛-①贪心②前缀和+暴力枚举/前缀和+三指针滑动窗口③分层图最短路④二分答案

507周赛-①贪心②前缀和+暴力枚举/前缀和+三指针滑动窗口③分层图最短路④二分答案#

Q1-贪心#

题目#

给你一个由字符 'U''D''L''R' 和 '_' 组成的字符串 moves

从原点 (0, 0) 出发,每个字符表示二维平面上的一次移动:

  • 'U':向上移动 1 个单位。
  • 'D':向下移动 1 个单位。
  • 'L':向左移动 1 个单位。
  • 'R':向右移动 1 个单位。
  • '_':可以独立地替换为 'U''D''L' 或 'R' 中的任意一个字符。

返回执行完所有移动后,能够达到的距离原点的 最大曼哈顿距离 。

两点 (x1, y1) 和 (x2, y2) 之间的 曼哈顿距离为 |x1- x2| + |y1- y2|

贪心#

贪心
class Solution:
def maxDistance(self, moves: str) -> int:
x = y = 0
ans = 0
for ch in moves:
if ch == 'U':
y += 1
elif ch == 'D':
y -= 1
elif ch == 'L':
x -= 1
elif ch == 'R':
x += 1
else:
ans += 1
return abs(x) + abs(y) + ans

Q2-前缀和+暴力枚举/前缀和+三指针滑动窗口#

题目#

给你一个整数数组 nums 和一个整数数字 x

如果一个 子数组 nums[l..r] 的元素和同时满足以下两个条件,则认为该子数组是有效子数组

  • 该和的首位数字等于 x
  • 该和的末位数字等于 x

返回有效子数组的数量。

子数组是数组中一个连续 、非空 的元素序列。

前缀和+暴力#

枚举子数组的左右端点。

在枚举右端点的同时,维护子数组的元素和 s。

前缀和+暴力
class Solution:
def countValidSubarrays(self, nums: list[int], x: int) -> int:
n = len(nums)
pre = [0]*(n+1)
for i in range(n):
pre[i+1] = pre[i] + nums[i]
ans = 0
for l in range(n):
for r in range(l,n):
sub = pre[r+1] - pre[l]
last = sub%10
if last != x:
continue
firs = int(str(sub)[0])
if firs == x:
ans += 1
return ans
非字符串
class Solution:
def countValidSubarrays(self, nums: list[int], x: int) -> int:
ans = 0
# 枚举子数组的左右端点
for i in range(len(nums)):
s = 0
for v in nums[i:]:
s += v
# 计算 s 的最低位
if s % 10 != x:
continue
# 计算 s 的最高位
t = s
while t > 9:
t //= 10
if t == x:
ans += 1
return ans

前缀和+三指针滑动窗口#

灵神题解地址:

3969. 求和后首尾数字相同的有效子数组 I - 力扣(LeetCode)

前缀和+三指针滑动窗口
class Solution:
def countValidSubarrays(self, nums: list[int], x: int) -> int:
pre = list(accumulate(nums, initial=0))
ans = 0
# 枚举子数组和的十进制长度
low, high = x, x + 1
while low <= pre[-1]:
# 计算子数组和在 [low, high-1] 中,且子数组和模 10 为 x 的子数组个数
cnt = [0] * 10
left1 = left2 = 0
for s in pre:
# 随着 s 的增大,<= s-high 的前缀和离开窗口,<= s-low 的前缀和进入窗口
while pre[left1] <= s - high:
cnt[pre[left1] % 10] -= 1
left1 += 1
while pre[left2] <= s - low:
cnt[pre[left2] % 10] += 1
left2 += 1
ans += cnt[(s - x) % 10]
low *= 10
high *= 10
return ans

Q3-分层图最短路#

题目#

给你一个整数 n,表示一个 有向加权图中的节点数量,节点编号从 0 到 n - 1。该图由二维数组 edges 表示,其中 edges[i] = [ui, vi, wi] 表示一条从节点 ui 指向节点 vi、权重为 wi 的有向边。

另给定一个长度为 n 的字符串 labels,其中 labels[i] 是分配给节点 i 的字符,以及一个整数 k

返回一条从节点 0 到节点 n - 1 的路径的 最小总边权,并要求该路径上所有节点标签按顺序 拼接后,最多包含 k 个 连续相同字符。如果不存在有效路径,返回 -1

分层图最短路#

定义 dis[x][cnt] 表示从节点 0 到节点 x 的最短路长度,且最后连续相同字母个数为 cnt

初始值 dis[0][1]=0

对于边权为 w 的边 x→y,分类讨论:

如果 labels[x]=labels[y],那么重新计数,用 dis[x][cnt]+w 更新 dis[y][1] 的最小值。 如果 labels[x]=labels[y]cnt+1≤k,那么累加连续相同字母个数,用 dis[x][cnt]+w 更新 dis[y][cnt+1] 的最小值。 注:根据 Dijkstra 算法的原理,当节点 n−1 首次出堆时,我们就算出了从节点0 到节点 n−1 的最短路,可以直接返回答案。

分层图最短路
class Solution:
def shortestPath(self, n: int, edges: List[List[int]], labels: str, k: int) -> int:
g = [[] for _ in range(n)]
for u,v,w in edges:
g[u].append((v,w))
lab = [ord(c) - ord('a') for c in labels]
vis = set()
pq = [(0,0,1,lab[0])]
while pq:
w,node,l,ch = heapq.heappop(pq)
if node == n-1:
return w
st = (node,l,ch)
if st in vis:
continue
vis.add(st)
for ne,ne_w in g[node]:
ne_ch = lab[ne]
if ne_ch == ch:
n_l = l + 1
if n_l > k:
continue
else:
n_l = 1
n_st = (ne,n_l,ne_ch)
if n_st not in vis:
heapq.heappush(pq,(w+ne_w,ne,n_l,ne_ch))
return -1

Q4-二分答案#

题目#

给你两个整数数组 value 和 decay,以及一个整数 m

  • value[i] 表示下标 i 的初始价值。
  • decay[i] 表示每次选择下标 i 后,该下标的价值会减少的数值。

你可以多次选择 任意下标。所有下标的总选择次数不得超过 m

如果重复选择下标 i,第 t 次(从 1 开始计数)获得的价值为 value[i] - decay[i] * (t - 1)

返回你能够获得的最大总价值。由于答案可能很大,请返回其对 109 + 7 取模后的结果。

二分答案#

二分答案
class Solution:
def maxTotalValue(self, value: list[int], decay: list[int], m: int) -> int:
def check(low: int) -> bool:
left_m = m
for v, d in zip(value, decay):
if v >= low:
left_m -= (v - low) // d + 1
if left_m < 0: # 提前跳出循环
return True
return False
left, right = 0, max(value) + 1
while left + 1 < right:
mid = (left + right) // 2
if check(mid):
left = mid
else:
right = mid
low = left
ans = 0
# 计算价值严格大于 low 的价值和,以及这些价值的个数
for v, d in zip(value, decay):
if v > low:
k = (v - low - 1) // d + 1
m -= k
ans += (v * 2 - d * (k - 1)) * k
ans //= 2 # 把除以 2 提到循环外面
ans += m * low # 剩余 m 次选的价值都是 low
return ans % 1_000_000_007
507周赛-①贪心②前缀和+暴力枚举/前缀和+三指针滑动窗口③分层图最短路④二分答案
http://blog.7a7a68.xyz/posts/507周赛-贪心前缀和暴力枚举-前缀和三指针滑动窗口分层图最短路-二分答案/
作者
Waning
发布于
2026-06-21
许可协议
CC BY-NC-SA 4.0
Profile Image of the Author
Waning
愿你明日如绚丽之花.
公告
还活着.
音乐
封面

音乐

暂未播放

0:00 0:00
暂无歌词
分类
标签
站点统计
文章
56
分类
8
标签
20
总字数
125,693
运行时长
0
最后活动
0 天前

目录