第 15 题
答案与解析
第(1)小题
2
同一时刻有订单的店铺,每单加2,不再减1;无订单时才减1,且不低于0。优先级大于5才入榜,小于等于3才退榜;处于4或5时,保留此前的入榜状态。
按图15-3统计各时刻的订单,得到:
| 时刻 | 店铺1优先级 | 店铺2优先级 | 店铺3优先级 | 优先推荐名单 |
|---|---|---|---|---|
| 0 | 0 | 0 | 0 | 空 |
| 1 | 0 | 0 | 2 | 空 |
| 2 | 2 | 0 | 4 | 空 |
| 3 | 4 | 0 | 6 | 店铺3 |
| 4 | 3 | 2 | 5 | 店铺3 |
| 5 | 2 | 4 | 4 | 店铺3 |
| 6 | 1 | 6 | 6 | 店铺2、店铺3 |
店铺3在时刻3入榜,之后虽然降到5、4,但未降到3,仍在名单中;店铺2在时刻6入榜。因此时刻6有2家店铺。
第(2)①小题
C
程序分析
def bsort(data): # 列表 data 保存订单数据,每个订单数据为[时刻 t,店铺 id]
n = len(data)
c = 0
for i in range(n - 1):
for j in range(n - 1 - i):
if data[j][0] > data[j+1][0]:
data[j], data[j+1] = data[j+1], data[j]
elif data[j][0] == data[j+1][0] and data[j][1] > data[j+1][1]:
data[j], data[j+1] = data[j+1], data[j]
c += 1第一个条件比较相邻订单的时刻:左侧时刻较大才交换,使较早的订单向前移动。时刻相同则比较店铺id,左侧id较大才交换,使较小的id向前移动。时刻不同的订单由第一个条件决定次序,店铺id只参与同一时刻内部的比较。
解题思路
两个嵌套循环反复比较、交换相邻订单,内层比较范围逐轮缩小,这是冒泡排序的结构。每条订单为[时刻t,店铺id],两个分支使用不同的交换条件。
因此,时刻是第一排序依据,店铺id是同一时刻内的第二排序依据,两者均按从小到大的顺序排列。
第(2)②小题
2
共用程序分析见第(2)①小题。
c初值为0,且只有“时刻相同、左侧id较大”的elif分支执行c+=1,因此c统计同一时刻内id逆序造成的交换次数。时刻不同的订单交换时,不改变同一时刻订单之间的相对次序,可按原列表分组考察:
| 时刻 | 原列表中的id次序 | 升序次序 | 计入c的交换次数 |
|---|---|---|---|
| 1 | 3 | 3 | 0 |
| 2 | 3,1 | 1,3 | 1 |
| 3 | 3,1 | 1,3 | 1 |
| 4 | 2 | 2 | 0 |
| 5 | 2 | 2 | 0 |
| 6 | 2,3 | 2,3 | 0 |
c=1+1=2。
第(3)小题
tt - post[sid] - 1
st[sid] == False
val[sid] > 3
程序分析
bsort(data)
s = []
st = [False] * (n + 1)
val = [0] * (n + 1)
post = [0] * (n + 1)bsort按时刻、店铺id升序排列订单,使同一时刻、同一店铺的记录相邻。s初值为空;st、val、post按店铺编号访问,各项分别初始化为False或0。
i = j = 0
while i < m:
...
i = ji定位当前待处理的第一条订单,j向后寻找本组的结束位置。每轮末尾执行i=j,转入下一组。
while j < m and data[i] == data[j]:
j += 1
cnt = j - i
tt, sid = data[i][0], data[i][1]排序后,相同的[时刻,店铺id]记录连续排列。j在记录相同时增加,退出后下标i至j−1属于同一时刻、同一店铺,共cnt=j−i单;tt和sid分别取得该组时刻和店铺编号。
val[sid] -= ①
post[sid] = tt
if val[sid] < 0:
val[sid] = 0
# 原题修改:新增以下三行,处理无订单期间优先级降至3及以下时的退榜。
if val[sid] <= 3 and st[sid]:
st[sid] = False
s.remove(sid)
val[sid] += cnt * 2先扣减val[sid]并将负值归零,随后按本组订单数增加cnt*2,与优先级的变化规则对应,因此val保存店铺优先级。post[sid]在本轮更新为tt,所以扣减发生时,它保存该店铺上一次有订单的时刻,首次处理时为0。
加上本组订单分数之前,程序先检查扣减后的优先级:若已降到3及以下且st[sid]为True,就将标记置False并从s删除该店铺。这一步先处理无订单期间的退榜,再处理当前订单,保留了先退榜、后重新判断是否入榜的时间顺序。
if val[sid] > 5:
if ②:
st[sid] = True
s.append(sid) # 将 sid 添加到列表 s 的末尾
k = len(s) - 1
while s[k] < s[k - 1] and k >= 1:
s[k - 1], s[k] = s[k], s[k - 1]
k -= 1当前订单计分后,优先级超过5才进入入榜分支。满足空②时,将st[sid]置True并把sid加入s;结合前面的退榜操作可知,st记录该店铺在最近一次处理后的入榜状态,s保存相应店铺编号。追加的新编号从表尾逐次向左交换,使s保持升序。其他店铺尚未结算到当前时刻,其状态会在下次有订单时或最终输出前更新。
print("优先推荐店铺名单:")
for sid in s:
if post[sid] < T:
val[sid] -= T - post[sid]
if ③:
print("店铺", sid)订单全部处理完后,s中的店铺在各自最后一次订单处理后仍处于入榜状态。post[sid]之后到T没有新订单,需再扣去T−post[sid],由空③判断它是否仍应输出。这里只筛选最终名单,不再修改s;即使扣减结果为负,也会被退榜阈值排除。
填空分析
①
上一次有订单的时刻为post[sid],本次为tt;两次有订单的时刻均不扣分,中间无订单的时刻为post[sid]+1至tt−1,共tt−post[sid]−1个。因此填:
tt - post[sid] - 1
首次处理时post[sid]=0,对应扣除时刻1至tt−1;相邻时刻都有订单时,扣减量为0。
②
外层条件已经保证优先级大于5。若该店铺仍在名单中,不应重复追加;尚未入榜或已经退榜时,st[sid]为False,才需要加入。因此填:
st[sid] == False
③
能进入最后的for循环,说明该店铺在最后一次处理订单后仍在名单中。此后没有订单,优先级只会降低,降到3及以下才退榜,所以最终仍大于3就应输出,填:
val[sid] > 3
这里判断的是已经入榜的店铺是否继续保留,优先级为4或5时也应输出。例如时刻1有3单时优先级为6,时刻2无订单降为5,T=2时仍在名单中。
问题反馈
解析有疑问或显示异常?请先复制题目信息,再打开反馈表单填写。
题目编号:2026_04_G3_jinhuashixiao_q015
