区间 +1 操作搭出目标高度序列的最少次数:贪心累加每个位置比左邻高出的部分(差分正部之和),O(n) 一遍扫描。
OJ: roj
题目 ID: 3611
难度:普及+/提高-
标签:贪心差分NOIP
创建: 2026-10-02 10:45
更新: 2026-10-10 11:30
形式化题目
目标高度序列
正解
思路
1. 贪心 / 差分视角
每次操作是一段连续区间 +1,相当于在差分数组上做「
的位置必须由「覆盖 且不覆盖 」的操作开启,至少 次; 的位置可以被左边延伸的操作顺带覆盖,不新增次数。
因此最少操作数 =
2. 直观理解
从左到右搭:遇到比左边高的部分必须新开操作(爬升段),下降段直接让之前的操作提前结束,不花额外次数。
代码
cpp
/**
* Author by Rainboy blog: https://rainboylv.com github: https://github.com/rainboylvx
* rbook: -> https://rbook.roj.ac.cn https://rbook2.roj.ac.cn
* rainboy的学习导航网站: https://idx.roj.ac.cn
* create_at: 2026-10-10 11:30
* update_at: 2026-10-10 11:30
*/
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
int main(){ios::sync_with_stdio(false); cin.tie(nullptr); int n; if(!(cin>>n)) return 0; ll prev=0,total=0; for(int i=0;i<n;i++){ll h;cin>>h; if(h>prev) total+=h-prev; prev=h;} cout<<total<<'\n'; return 0;}python
#!/usr/bin/env python3
# Author by Rainboy blog: https://rainboylv.com github: https://github.com/rainboylvx
# rbook: -> https://rbook.roj.ac.cn https://rbook2.roj.ac.cn
# rainboy的学习导航网站: https://idx.roj.ac.cn
# create_at: 2026-10-02 10:42
# update_at: 2026-10-02 10:42
import sys
def min_operations(heights: list[int]) -> int:
"""最少操作数:从 0 起,逐块累加"比左邻高出的部分",下降段贡献 0。"""
prev = 0 # 左边没有积木,虚拟高度 0
total = 0
for height in heights:
if height > prev: # 这段爬升必须由不覆盖左邻的操作补齐
total += height - prev
prev = height
return total
def solve() -> None:
data = iter(map(int, sys.stdin.buffer.read().split()))
n = next(data)
heights = [next(data) for _ in range(n)] # 第 i 块的目标高度 h_i
print(min_operations(heights))
if __name__ == "__main__":
solve()复杂度
- 时间复杂度:
。 - 空间复杂度:
(读入数组;可流式 )。
总结
- 「区间 +1 凑目标」= 差分正部求和,经典贪心。
- 相邻差分的正负分解是所有「区间加减计数」问题的基本功。