【笔试刷题】网易-2026.03.08-改编真题

✅ 春招备战指南 ✅

💡 学习建议:

  • 先尝试独立解题
  • 对照解析查漏补缺

🧸 题面描述背景等均已深度改编,做法和题目本质基本保持一致。

🍹 感谢各位朋友们的订阅,你们的支持是我们创作的最大动力

🌸 目前本专栏已经上线200+套真题改编解析,后续会持续更新的

春秋招笔试机考招合集 -> 互联网必备刷题宝典🔗

网易-2026.03.08

这套网易题虽然只有两道,但都不是照着样子硬模拟就能稳过的类型。第一题要先分清“人走了多远”和“灯杖动了多远”不是一回事;第二题则要把“整次滚动”当成一条边,而不是把每个路过格子都拿来做决策点。

题目一:巡夜灯杖交接

这题最容易错在空队取杖阶段。最近的人只是先走过去接杖,那一段灯杖本身并没有移动,不能误算进贡献;把这个边界理顺后,整题就是按事件顺序做一次队列模拟。

难度:Mid

题目二:镜厅滚动寻路

真正的关键不是普通 BFS,而是先认清“只有静止时才能选方向”。把单次滚动预处理成“成功 / 停下 / 死循环”之后,再在静止点上做 BFS,结构就会一下子清楚很多。

难度:High

巡夜灯杖交接

问题描述

夜巡队要沿着一条笔直的长廊巡逻。

一共有 名巡逻员,第 名巡逻员最初站在位置 ,自己的终点是位置 ,满足 。所有人的起点两两不同,并且输入时已经按位置从小到大排好,也就是

一开始,只有第 名巡逻员拿着灯杖,并从位置 出发。

接下来会发生如下过程:

  • 当当前拿灯杖的人经过某位尚未加入队伍的巡逻员起点时,这名巡逻员会立刻加入队尾。

  • 当某名巡逻员到达自己的终点 时,他会立刻离队,并且之后不会再次加入队伍。

  • 如果离队的人正好拿着灯杖,那么:

    • 若此时队伍不为空,灯杖交给新的队首。
    • 若此时队伍为空,灯杖会停在当前位置不动。此后,所有尚未加入过队伍的人中,起点离当前灯杖位置最近的那个人会先走到这里拿起灯杖,再继续前往自己的终点;如果他在去拿灯杖的路上经过了其他尚未加入过队伍的人的起点,这些人也会按经过顺序加入队尾。

题目保证最近的人总是唯一确定的。

定义第 名巡逻员的贡献值为:他拿着灯杖时,灯杖实际移动的总距离。请输出所有人的贡献值。

输入格式

第一行输入一个整数 ,表示巡逻员人数。

接下来 行,每行输入两个整数 ,表示第 名巡逻员的起点和终点。

输出格式

输出一行 个整数,第 个整数表示第 名巡逻员的贡献值。

样例输入

4
1 10
5 6
9 30
20 25

样例输出

9 0 20 0

数据范围

样例 解释说明
样例 1 人先把灯杖从位置 带到位置 ,贡献是 。第 人接手时,自己的终点位置 已经被越过,所以立刻离队,贡献是 。最后第 人把灯杖从位置 带到位置 ,贡献是 。第 人虽然途中加入了队伍,但始终没有真正把灯杖向前带动,所以贡献也是

题解

这题看起来像很多人来回交接,真正要抓住的只有两件事:

  • 灯杖的位置只会在“当前持有者继续向自己的终点前进”时发生变化。
  • 一旦某个人接手时,发现自己的终点已经不在当前位置右边,那么他会立刻离队,贡献是

所以可以直接做事件模拟。

先维护下面几样状态:

  • u:当前灯杖所在位置。
  • h:当前拿灯杖的人编号,如果现在没人拿,就记成 -1
  • 一个队列,表示已经加入但还没拿到灯杖的人。
  • joined[i]:第 个人是否已经加入过队伍。

h != -1 时,当前持有者只会面临两个下一事件:

  • 先经过某个还没加入的人的起点。
  • 先到达自己的终点。

因为起点有序,可以直接在线性扫描里找出当前位置右边最近的未加入起点。然后比较这个起点和当前持有者终点,谁更靠左,谁就是下一事件:

  • 如果先经过起点,那么灯杖移动到那个位置,这一段距离计入当前持有者贡献,新人入队。
  • 如果先到达终点,那么灯杖移动到终点,这一段距离同样计入当前持有者贡献,然后当前持有者离队,把灯杖交给下一位。
  • 如果二者恰好在同一位置,就先让新人加入,再让当前持有者离队。

h == -1 且队列也为空时,说明灯杖停住了。此时要从所有未加入的人里找出起点离 u 最近的人,让他走过来拿灯杖。

这里有一个容易误会的点:这个人是“先走到灯杖那里,再拿起灯杖继续前进”,所以他走过来这段路上,灯杖本身并没有移动,这一段距离不能算进贡献。

不过,他在路上经过的其他未加入起点,依然会按经过顺序入队。这个顺序只和他从自己的起点走向 u 的方向有关:

  • 如果是从左往右走,就按起点从小到大入队。
  • 如果是从右往左走,就按起点从大到小入队。

等他走到 u 之后,再把他设成新的持有者,继续模拟即可。

为什么这样做不会漏情况?

  • 题目里的所有变化,本质上只有“某人加入”和“某人离队”这两类事件。
  • 每次只需要处理最靠前的那个事件,处理后系统状态就会更新成下一段完全一样的问题。
  • 队列顺序严格由题意给定,任何时候都不需要回退,所以整个过程可以顺着时间一直推下去。

复杂度方面,人数只有 。每次找下一事件、找最近未加入的人,最多都是扫一遍所有人。总事件数也是 级别,因此总时间复杂度是 ,空间复杂度是 ,完全够用。

参考代码

Python

import sys
from collections import deque

input = lambda: sys.stdin.readline().strip()


def solve() -> None:
    n = int(input())
    p = [0] * n
    q = [0] * n
    for i in range(n):
        p[i], q[i] = map(int, input().split())

    # joined[i] 表示第 i 个人是否已经加入过队伍。
    joined = [False] * n
    # ans[i] 记录第 i 个人持灯杖时,灯杖真正移动的总距离。
    ans = [0] * n
    que = deque()

    # 初始时,第 0 个人已经加入并拿着灯杖。
    joined[0] = True
    h = 0
    u = p[0]
    left_cnt = 0

    while left_cnt < n:
        if h != -1:
            # 如果当前持有者的终点已经在当前位置左边或重合,
            # 那么他会立刻离队,灯杖不再移动。
            if q[h] <= u:
                left_cnt += 1
                if que:
                    h = que.popleft()
                else:
                    h = -1
                continue

            # 找到当前位置右边最近的未加入起点。
            nxt_pos = None
            nxt_id = -1
            for i in range(n):
                if not joined[i] and p[i] > u:
                    if nxt_pos is None or p[i] < nxt_pos:
                        nxt_pos = p[i]
                        nxt_id = i

            leave_pos = q[h]

            if nxt_pos is not None and nxt_pos < leave_pos:
                # 先经过新人的起点。
                ans[h] += nxt_pos - u
                u = nxt_pos
                joined[nxt_id] = True
                que.append(nxt_id)
            elif nxt_pos is not None and nxt_pos == leave_pos:
                # 同一位置同时发生“新人加入”和“当前持有者离队”,
                # 题意要求先加入,再交接。
                ans[h] += nxt_pos - u
                u = nxt_pos
                joined[nxt_id] = True
                que.append(nxt_id)
                left_cnt += 1
                if que:
                    h = que.popleft()
                else:
                    h = -1
            else:
                # 先到达当前持有者的终点。
                ans[h] += leave_pos - u
                u = leave_pos
                left_cnt += 1
                if que:
                    h = que.popleft()
                else:
                    h = -1
        else:
            # 现在没人拿灯杖,需要找最近的未加入者去把灯杖接起来。
            best_dis = None
            ni = -1
            for i in range(n):
                if not joined[i]:
                    d = abs(p[i] - u)
                    if best_dis is None or d < best_dis:
                        best_dis = d
                        ni = i

            # 他是从 p[ni] 走到 u,中途经过的人会按经过顺序入队。
            tmp = []
            lo = min(p[ni], u)
            hi = max(p[ni], u)
            for i in range(n):
                if not joined[i] and i != ni and lo < p[i] < hi:
                    tmp.append(i)

            # 如果是从左往右走,经过顺序就是起点递增;
            # 如果是从右往左走,经过顺序就是起点递减。
            if p[ni] < u:
                tmp.sort(key=lambda x: p[x])
            else:
                tmp.sort(key=lambda x: p[x], reverse=True)

            for i in tmp:
                joined[i] = True
                que.append(i)

            # 注意:这个人走到灯杖处之前,灯杖没有移动,
            # 所以这里不能把 abs(p[ni] - u) 加进贡献。
            joined[ni] = True
            h = ni

    print(*ans)


if __name__ == "__main__":
    solve()

Cpp

#include <deque>
#include <iostream>
#include <vector>
using namespace std;

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    int n;
    cin >> n;
    vector<long long> p(n), q(n);
    for (int i = 0; i < n; ++i) {
        cin >> p[i] >> q[i];
    }

    // joined[i] 表示第 i 个人是否已经加入过队伍。
    vector<int> joined(n, 0);
    // ans[i] 统计第 i 个人真正让灯杖移动了多远。
    vector<long long> ans(n, 0);
    deque<int> que;

    joined[0] = 1;
    int h = 0;
    long long u = p[0];
    int leftCnt = 0;

    while (leftCnt < n) {
        if (h != -1) {
            // 当前持有者的终点已经被越过时,会立刻离队。
            if (q[h] <= u) {
                ++leftCnt;
                if (!que.empty()) {
                    h = que.front();
                    que.pop_front();
                } else {
                    h = -1;
                }
                continue;
            }

            // 在当前位置右边,找最近的未加入起点。
            long long nxtPos = -1;
            int nxtId = -1;
            for (int i = 0; i < n; ++i) {
                if (!joined[i] && p[i] > u) {
                    if (nxtPos == -1 || p[i] < nxtPos) {
                        nxtPos = p[i];
                        nxtId = i;
                    }
                }
            }

            long long leavePos = q[h];

            if (nxtId != -1 && nxtPos < leavePos) {
                // 先路过新的起点,新人直接入队。
                ans[h] += nxtPos - u;
                u = nxtPos;
                joined[nxtId] = 1;
                que.push_back(nxtId);
            } else if (nxtId != -1 && nxtPos == leavePos) {
                // 同一点既有人加入,也有人离队,先加入再交接。
                ans[h] += nxtPos - u;
                u = nxtPos;
                joined[nxtId] = 1;
                que.push_back(nxtId);
                ++leftCnt;
                if (!que.empty()) {
                    h = que.front();
                    que.pop_front();
                } else {
                    h = -1;
                }
            } else {
                // 先到终点,当前持有者离队。
                ans[h] += leavePos - u;
                u = leavePos;
                ++leftCnt;
                if (!que.empty()) {
                    h = que.front();
                    que.pop_front();
                } else {
                    h = -1;
                }
            }
        } else {
            // 灯杖停住时,找最近的未加入者来接。
            long long bestDis = -1;
            int ni = -1;
            for (int i = 0; i < n; ++i) {
                if (!joined[i]) {
                    long long d = p[i] > u ? p[i] - u : u - p[i];
                    if (bestDis == -1 || d < bestDis) {
                        bestDis = d;
                        ni = i;
                    }
                }
            }

            vector<int> tmp;
            long long lo = min(p[ni], u);
            long long hi = max(p[ni], u);
            for (int i = 0; i < n; ++i) {
                if (!joined[i] && i != ni && lo < p[i] && p[i] < hi) {
                    tmp.push_back(i);
                }
            }

            // 按“走去拿灯杖”的经过顺序入队。
            if (p[ni] < u) {
                for (int i = 0; i < (int)tmp.size(); ++i) {
                    for (int j = i + 1; j < (int)tmp.size(); ++j) {
                        if (p[tmp[i]] > p[tmp[j]]) {
                            swap(tmp[i], tmp[j]);
                        }
                    }
                }
            } else {
                for (int i = 0; i < (int)tmp.size(); ++i) {
                    for (int j = i + 1; j < (int)tmp.size(); ++j) {
                        if (p[tmp[i]] < p[tmp[j]]) {
                            swap(tmp[i], tmp[j]);
                        }
                    }
                }
            }

            for (int id : tmp) {
                joined[id] = 1;
                que.push_back(id);
            }

            // 走过来接灯杖这段,灯杖本身没动,不能计入贡献。
            joined[ni] = 1;
            h = ni;
        }
    }

    for (int i = 0; i < n; ++i) {
        if (i) {
            cout << ' ';
        }
        cout << ans[i];
    }
    cout << '\n';
    return 0;
}

Java

import java.io.BufferedInputStream;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;

public class Main {
    static class FastScanner {
        private final BufferedInputStream in = new BufferedInputStream(System.in);
        private final byte[] buf = new byte[1 << 16];
        private int len = 0;
        private int ptr = 0;

        private int read() throws Exception {
            if (ptr >= len) {
                len = in.read(buf);
                ptr = 0;
                if (len <= 0) {
                    return -1;
                }
            }
            return buf[ptr++];
        }

        long nextLong() throws Exception {
            int c;
            do {
                c = read();
            } while (c <= ' ' && c != -1);

            long sign = 1;
            if (c == '-') {
                sign = -1;
                c = read();
            }

            long val = 0;
            while (c > ' ') {
                val = val * 10 + c - '0';
                c = read();
            }
            return val * sign;
        }
    }

    public static void main(String[] args) throws Exception {
        FastScanner fs = new FastScanner();
        int n = (int) fs.nextLong();
        long[] p = new long[n];
        long[] q = new long[n];
        for (int i = 0; i < n; ++i) {
            p[i] = fs.nextLong();
            q[i] = fs.nextLong();
        }

        boolean[] joined = new boolean[n];
        long[] ans = new long[n];
        ArrayDeque<Integer> que = new

剩余60%内容,订阅专栏后可继续查看/也可单篇购买

互联网刷题笔试宝典 文章被收录于专栏

互联网刷题笔试宝典,这里涵盖了市面上大部分的笔试题合集,希望助大家春秋招一臂之力

全部评论

相关推荐

评论
2
1
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务