NKOJ 3540 方块游戏(dp)

本文探讨了一种特殊的积木游戏,通过使用一种特殊工具调整积木高度,使积木排列符合“山峰”定义的过程。介绍了如何计算最少操作次数以实现目标,并提供了具体的算法思路及代码实现。

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

P3540积木游戏

问题描述

小时候我们都喜欢玩积木。这里的积木都是单位边长的正方体块,多个积木可以堆成一个“高木”,“高木”的高度就是叠放的积木块个数。多个“高木”形成一个排列,如果高度满足先严格上升再严格下降,则称这个排列为一座山峰。严格的定义是:假设有N个高木从左到右排列,第i个高度为H[i](i=1,2,...,N)。那么如果存在一个整数k[2,N-1],使得对所有的位置i,下式都成立,则称H是一座山峰。
H[i]>H[i-1],1<i<=k
H[i]>H[i+1],k<i<=N
现在你有一个超级工具,每次操作可以给一段连续的区间各位置都叠放上一块积木,使得高度同时增加1个单位,现在有一个“高木”排列,需要将其改造为一座山峰,只允许使用这种超级工具,最少需要操作几次可以达到这个目标呢?假设积木无限供应。

输入格式

输入文件只有一组数据。
第一行包含一个整数N,为上文提到的初始排列中“高木”的个数。
第二行包含N个正整数,表示由左到右的N个位置“高木”的初始高度H[i],数字由空格隔开。

输出格式

输出包含一个整数,表示所需要的最少的操作次数。

样例输入

6 
3 4 3 6 7 8

样例输出

2

提示

对于30%的数据,满足N<=20,H[i]<=50.
对于50%的数据,满足N<=100,H[i]<=1000
对于全部的数据,满足3<=N<=10^5,H[i]<=10^7

此题我们考虑计算两个值,L[i]表示将1-i区间变成递增需要的最少操作次数,R[i]表示将i-n区间变成递减区间的最少操作次数。
计算L[i]的时候,我们如果要增加i号点的高度,那么显然这次操作同时增加in是最优的,因为这不会影响后面方块的高度差,然而如果只增加i号点,那么后面需要额外一次操作来形成递增序列。R[i]同理。
那么最后ans=min{max(L[i],R[i])}。因为次数较少的一边肯定可以在另一边的操作的同时完成。


代码:

#include<stdio.h>
#include<iostream>
#include<algorithm>
#define N 123456
using namespace std;
int n,A[N],L[N],R[N],ans=1e9;
int main()
{
    int i,j,k,tmp;
    scanf("%d",&n);
    for(i=1;i<=n;i++)scanf("%d",&A[i]);
    for(i=2;i<=n;i++)
    {
        if(A[i]<=A[i-1])L[i]=A[i-1]+L[i-1]+1-A[i];
        else L[i]=L[i-1];
    }
    for(i=n-1;i>=1;i--)
    {
        if(A[i]<=A[i+1])R[i]=A[i+1]+R[i+1]+1-A[i];
        else R[i]=R[i+1];
    }
    for(i=1;i<=n;i++)ans=min(ans,max(L[i],R[i]));
    cout<<ans;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值