题解:学而思编程 感应门

【题目来源】

学而思编程:感应门

【题目描述】

感应门会在有人经过的时候自动打开,冷却 \(d\) 秒后自动关闭。如果在门打开的时候有人通过,那么冷却时间会重置,重新冷却 \(d\) 秒后再关闭。

在一段时间内,有 \(n\) 个人陆续通过了感应门,他们通过感应门的时间点分别是 \(t_1,t_2,\cdots,t_n\)。请计算感应门一共开放了多少时间。

【输入】

第一行两个正整数 \(n, d\)\(n\) 表示通过感应门的人数,\(d\) 表示感应门的冷却时间;

第二行 \(n\) 个正整数 \(t_1,t_2,\cdots,t_n\),每个数字表达一个人通过感应门的时间点。

【输出】

一行一个整数,表示感应门总共开启了多少时间。

【输入样例】

7 3
1 2 7 10 15 17 22

【输出样例】

18

【核心思想】

  1. 问题分析:感应门在有人经过时打开,冷却 \(d\) 秒后关闭。若门打开期间有人通过,冷却时间重置。给定 \(n\) 个人通过的时间点,求门总开启时间。这是一个区间合并 + 贪心模拟问题,关键在于将连续的开启区间合并,避免重复计算。

  2. 算法选择

    • 维护当前区间:记录当前开门时间段 [open, close)
    • 事件驱动:按时间点顺序处理每个人,判断是延长当前区间还是开启新区间
  3. 关键步骤

    • 初始化
      • 读取 \(n\)(人数)和 \(d\)(冷却时间)
      • 读取第一个时间点 \(t\)
      • open = t:当前开门开始时间
      • close = open + d:当前关门时间
      • ans = 0:累计开启时间
    • 处理后续事件(遍历 \(i\)\(2\)\(n\)):
      • 读取下一个时间点 \(t\)
      • t < close(在关门前有新人通过):
        • close = t + d:延长关门时间(冷却重置)
      • 否则(关门后才有新人通过):
        • ans += close - open:累加前一段开启时间
        • open = t:开启新时间段
        • close = t + d
    • 加上最后一段
      • ans += close - open:处理最后一个区间的开启时间
    • 输出 ans
  4. 时间/空间复杂度

    • 时间复杂度:\(O(n)\),线性遍历时间点
    • 空间复杂度:\(O(1)\),仅需常数变量
  5. 区间合并的核心思想

    • 事件时间排序:时间点天然按顺序给出,无需额外排序
    • 区间连续性判断:若新事件在 close 之前,说明当前门仍开着,只需延长 close;否则前一段结束,累加并开启新段
    • 冷却重置机制close = t + d 而非 close + d,确保从最新事件时刻重新冷却 \(d\)
    • 最后区间处理:循环结束后最后一个区间尚未累加,需单独加上
    • 适用于"时间区间合并 + 重置机制"类问题,贪心维护当前区间即可实现最优合并

【算法标签】

模拟

【代码详解】

#include <bits/stdc++.h>
using namespace std;

int n;  // 事件数量
int t;  // 临时变量,用于输入时间
int x;  // 每次开门后的持续时间
int ans;  // 总开门时间

int main()
{
    cin >> n >> x >> t;  // 输入事件数量、持续时间、第一个事件时间

    int open = t;  // 当前开门开始时间
    int close = open + x;  // 当前开门结束时间

    for (int i = 1; i <= n; i++)
    {
        cin >> t;  // 输入下一个事件的时间

        if (t < close)  // 如果事件在关门之前发生
        {
            close = t + x;  // 延长关门时间
        }
        else  // 如果事件在关门之后发生
        {
            ans += close - open;  // 累加前一段开门时间
            open = t;  // 新的开门开始时间
            close = t + x;  // 新的关门时间
        }
    }

    // 加上最后一段开门时间
    cout << ans + close - open << endl;

    return 0;  // 程序正常结束
}

【运行结果】

7 3
1 2 7 10 15 17 22
18
posted @ 2026-07-05 14:46  团爸讲算法  阅读(3)  评论(0)    收藏  举报