求从N到1的最少操作次数(仅允许加减1或除2)

本文探讨了如何在仅能进行加1、减1或乘2的操作下,找到从1变化到N所需的最少步骤。通过动态规划的方法,定义状态转移方程并给出了解决方案。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目等价于:在只允许加、减1或乘2的前提下,求从1变到N的最少操作次数。

 

分析:任意一个中间数m,若m为偶数,则可能由m-1加1得到,或是由m/2乘2得到;若m为奇数,则可能由m-1加1得到,或是由(m+1)/2经过乘2再减1得到,故可得递推式:

 

n为偶数: f(n) = min{f(n-1)+1, f(n/2)+1}

n为奇数: f(n) = min{f(n-1)+1, f((n+1)/2)+2}

初始值: f(0)=f(1)=0

 

 

``` #include<bits/stdc++.h> using namespace std; int n,a[100005]; long long ans=0; int main(){ cin>>n; for(int i=1;i<=n;i++)cin>>a[i]; for(int i=2;i<=n;i++)if(a[i]>a[i-1])ans+=a[i]-a[i-1]; cout<<ans+a[1]<<endl; return 0; }```题目重述 给定一个宽度为 n n 的大厦,初始所有积木高度为 0 0。每次操作可以选择一个连续区间 [ l , r ] [l,r],将该区间内所有积木高度 1 1最少操作次数,使得最终每个积木 i i 的高度达到给定的 h i h i ​ 。 深入分析 该题的核心是如何用最少的区间操作构造目标组,本质属于贪心算法中的区间覆盖题。我们需要挖掘以下关键性质: 操作性:每个操作独立,最终高度是各操作区间的叠结果。 操作连续性:每次必须选择连续区间,这限制了操作的灵活性。 操作顺序无关性:最终高度与操作顺序无关,只需关注总次数。 关键观察 纵向高度变化 若 h [ i ] > h [ i − 1 ] h[i]>h[i−1],则必须新增 h [ i ] − h [ i − 1 ] h[i]−h[i−1] 次从 i i 开始向右延伸的操作(因为这些高度无法通过之前的操作覆盖)。 若 h [ i ] ≤ h [ i − 1 ] h[i]≤h[i−1],则可通过调整之前的操作区间覆盖,无需新增操作。 边界处理 第一个积木必须通过 h [ 1 ] h[1] 次覆盖它的操作(例如区间 [ 1 , 1 ] [1,1] [ 1 , k ] [1,k])。 最后一个积木的高度变化不会影响后续(因右侧无积木)。 严格证明(学归纳法) 归纳基础: 当 n = 1 n=1 时,显然需要 h [ 1 ] h[1] 次操作,算法正确。 归纳假设: 假设对于前 k − 1 k−1 个积木,算法能计算出最少操作次数。 归纳步骤: 考虑第 k k 个积木: 若 h [ k ] > h [ k − 1 ] h[k]>h[k−1],需新增 h [ k ] − h [ k − 1 ] h[k]−h[k−1] 次从 k k 开始的右延伸操作。 若 h [ k ] ≤ h [ k − 1 ] h[k]≤h[k−1],之前的操作已足够覆盖,无需新增。 因此,算法对前 k k 个积木仍成立。 算法实现 Cpp #include<bits/stdc++.h> using namespace std; int n, a[100005]; long long ans = 0; // 防止溢出 int main() { cin >> n; for (int i = 1; i <= n; i++) cin >> a[i]; for (int i = 2; i <= n; i++) if (a[i] > a[i-1]) ans += a[i] - a[i-1]; cout << ans + a[1] << endl; // 上第一个积木的操作次数 return 0; } 示例详解 输入: 5 2 3 4 1 2 计算过程: 初始操作次数为 a [ 1 ] = 2 a[1]=2。 a [ 2 ] = 3 > a [ 1 ] = 2 a[2]=3>a[1]=2 → 新增 3 − 2 = 1 3−2=1(总 3 3)。 a [ 3 ] = 4 > a [ 2 ] = 3 a[3]=4>a[2]=3 → 新增 4 − 3 = 1 4−3=1(总 4 4)。 a [ 4 ] = 1 ≤ a [ 3 ] = 4 a[4]=1≤a[3]=4 → 不新增。 a [ 5 ] = 2 > a [ 4 ] = 1 a[5]=2>a[4]=1 → 新增 21 = 1 21=1(总 5 5)。 输出: 2 + 1 + 1 + 1 = 5 2+1+1+1=5。 复杂度分析 时间复杂度: O ( n ) O(n)次遍历组。 空间复杂度: O ( n ) O(n),用于存储高度组。 边界情况 情况类型 示例输入 操作次数 解释 所有 h [ i ] h[i] 相同 ` 3 5 5 5` 5 5 只需覆盖整个区间 5 5 次 单调递增 ` 4 1 2 3 4` 4 4 每次从当前积木延伸到末尾 包含 0 0 高度 ` 3 0 2 1` 0 + 2 + 0 = 2 0+2+0=2 自动跳过 h [ 1 ] = 0 h[1]=0 的情况 与其他方法对比 方法 时间复杂度 实现难度 适用场景 暴力法 O ( 2 n ) O(2 n ) 极高 理论分析 差分法 O ( n ) O(n) 中等 需要记录具体操作 贪心法 O ( n ) O(n) 简单 竞赛与工程 实际应用 资源分配:在连续区域分配资源的最优策略。 图像渲染:矩形区域像素值调整的最少操作。 日程安排:连续时间段任务分配的最小批次。 常见错误 忽略第一个积木:未单独处理 h [ 1 ] h[1] 导致结果错误。 整溢出:未使用 long long 存储大结果。 错误理解操作方向:误认为需要从右向左处理。 总结 本题通过分析高度变化的局部特征,设计出时间复杂度为 O ( n ) O(n) 的贪心算法。核心思想是: 利用高度差:对需要新增操作的部分累次数。 边界处理:独立处理第一个积木的初始操作。 高效实现:代码简洁,直接遍历次数组即可。 该算法体现了贪心思想在区间覆盖题中的典型应用,具有极高的工程实用价值。针对这个题解,完善学证明部分
04-02
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值