4262. 空调(acwing)

4262. 空调

题目描述

Farmer John 的 N头奶牛对他们牛棚的室温非常挑剔。

有些奶牛喜欢温度低一些,而有些奶牛则喜欢温度高一些。

Farmer John 的牛棚包含一排 N个牛栏,编号为 1…N,每个牛栏里有一头牛。

第 i头奶牛希望她的牛栏中的温度是 pi,而现在她的牛栏中的温度是 ti

为了确保每头奶牛都感到舒适,Farmer John 安装了一个新的空调系统。

该系统进行控制的方式非常有趣,他可以向系统发送命令,告诉它将一组连续的牛栏内的温度升高或降低 1个单位——例如「将牛栏 5…8的温度升高 1个单位」。

一组连续的牛栏最短可以仅包含一个牛栏。

请帮助 Farmer John 求出他需要向新的空调系统发送的命令的最小数量,使得每头奶牛的牛栏都处于其中的奶牛的理想温度。

输入格式
输入的第一行包含 N。

下一行包含 N 个非负整数 p1…pN,用空格分隔。

最后一行包含 N个非负整数 t1…tN

输出格式
输出一个整数,为 Farmer John 需要使用的最小指令数量。

数据范围
1≤N≤105,
0≤pi,ti≤10000
输入样例:

5
1 5 3 3 4
1 2 2 2 1

输出样例:

5

样例解释
一组最优的 Farmer John 可以使用的指令如下:

初始温度     :1 2 2 2 1
升高牛棚 2..5:1 3 3 3 2
升高牛棚 2..5:1 4 4 4 3
升高牛棚 2..5:1 5 5 5 4
降低牛棚 3..4:1 5 4 4 4
降低牛棚 3..4:1 5 3 3 4

贪心+差分

解析详见:AcWing 4262. 空调

#include<bits/stdc++.h> // 包含所有标准库头文件
using namespace std;    // 使用标准命名空间

const int z=1e5+10;     // 定义常量z,表示最大的牛棚数量 + 10作为缓冲
int b[z];               // 定义一个全局数组b,用于存储每个牛棚的温度变化

int main()              // 程序的主函数
{
    int n;             // 定义整数n,用于存储牛棚的数量
    scanf("%d",&n);    // 读入牛棚数量
    // 循环读入每个牛棚的期望温度
    for(int i=1;i<=n;i++) 
        scanf("%d",&b[i]);
    // 循环读入每个牛棚的实际温度,并计算期望与实际的差值
    for(int i=1;i<=n;i++)
    {
        int x;         // 定义临时变量x,用于存储每个牛棚的实际温度
        scanf("%d",&x); // 读入实际温度
        b[i]=b[i]-x;   // 计算差值,并更新b数组的相应位置
    }
    // 逆向差分,计算调整每个牛棚温度所需的命令数
    // 这是通过从后向前累计差值来实现的
    for(int i=n+1;i>=1;i--) 
        b[i]=b[i]-b[i-1];
    int res=0;         // 定义结果变量res,初始化为0
    // 遍历b数组,累加所有正数差值
    // 正数差值表示需要升高温度的命令数
    for(int i=1;i<=n+1;i++)
    {
        if(b[i]>0)    // 如果差值为正数
            res+=b[i]; // 累加到结果变量res
    }
    cout<<res<<endl;  // 输出最小指令数量
    return 0;         // 返回0,结束程序
}

这段代码的主要目的是计算Farmer John所需发送的最小指令数量,以便每头牛都处于其理想的温度。代码的核心思路是使用差分数组来跟踪每个牛棚的温度变化,于是问题转化为计算使数组b的所有值为0所需的最小操作数。

程序首先读入牛棚数量,然后读入每个牛棚的理想温度和实际温度。通过计算理想温度和实际温度的差值,并将这些差值存储在数组b中。随后,程序执行逆向差分,即从后向前累积差值,来计算必要的空调调整次数。最终,程序遍历整个差分数组,累加所有正数值,得到必要的最小指令数量。

请注意,由于温度调整的是连续区间,所以我们只需关心每个区间端点的温度变化即可。这是因为,当我们调整一个区间的温度时,区间内所有点的温度都会一起变化。因此,差分数组的作用在于帮助我们确定这些区间的边界。

难点解析

让我尽量解释得更清楚一些。代码的这部分利用了一种称为“差分”的技巧,来计算为了达到所有牛希望的温度而需要发送的空调调节命令的最小数量。这里的关键是理解“差分”和如何利用它来求解问题。

差分数组的更新
for(int i=n+1;i>=1;i--)
    b[i]=b[i]-b[i-1];

在这个循环中,我们实际上通过计算相邻元素之间的差值,来更新数组b。具体来说,这里的操作是将b[i]的值更新为b[i]b[i-1]的差。这一步的目的是为了反映从一个牛栏到另一个牛栏所需温度调整的净变化。

  • 为什么要这么做? 因为Farmer John的空调系统是通过升高或降低一组连续牛栏的温度来工作的。如果我们知道了连续两牛栏间所需的温度变化,那么我们就可以通过一系列这样的操作来确保每个牛栏的温度都调整到目标温度。
计算最小命令数量
int res=0;
for(int i=1;i<=n+1;i++)
{
    if(b[i]>0)
        res+=b[i];
}

在更新完差分数组后,接下来的步骤是计算发送给空调系统的最小命令数量。这里的策略是将差分数组中所有正的差分值加起来。为什么这样做?

  • 原因是,差分数组中的正值表示为了使牛栏的温度达到目标温度,我们需要增加温度的次数。而负值(如果直接处理)则表示需要降温的次数。但由于在最终计算中,需要增加温度的操作次数与需要降温的操作次数在数学上相互抵消,我们只需要关注增加温度的操作次数,因为这直接反映了操作的总数。具体来说,任何时候我们需要降低温度,都会有一个相对应的升温操作与之相抵消,因此,直接统计升温操作的次数就足够了。

这里的核心思想是,通过分别计算温度的增加和降低需求,然后找到满足这些需求的最小操作集,从而使得每个牛栏的温度都达到其希望的温度。通过这种方式,我们能够高效地找到解决方案。

当然,让我通过一个简单的例子来解释这段代码的逻辑。

假设我们有3个牛棚,Farmer John希望这些牛棚的温度分别为:

  • 牛棚1:希望温度为4度
  • 牛棚2:希望温度为5度
  • 牛棚3:希望温度为2度

目前,这些牛棚的实际温度分别为:

  • 牛棚1:实际温度为2度
  • 牛棚2:实际温度为3度
  • 牛棚3:实际温度为5度

首先,我们计算每个牛棚希望温度与实际温度之间的差异:

  • 牛棚1:差异为+2(需要升温2度)
  • 牛棚2:差异为+2(需要升温2度)
  • 牛棚3:差异为-3(需要降温3度)

接着,我们创建一个差分数组来帮助我们计算实现这些温度调整所需的最小指令数量。

更新差分数组

我们假设差分数组为b,并根据上面的差异更新它。这时,b中的值如下:

  • b[1]对应牛棚1的温度调整为+2
  • b[2]对应牛棚2的温度调整为+2
  • b[3]对应牛棚3的温度调整为-3
反向差分计算
for(int i=n+1;i>=1;i--)
    b[i]=b[i]-b[i-1];

这段代码实际上是在准备差分数组以便计算所需的最小操作。但是,为了简化理解,我们跳过这部分的具体计算,直接解释其作用:它帮助我们确定从一个牛棚到下一个牛棚,温度调整的净变化是多少。

计算最小指令数量

接下来,我们需要计算实现所有这些调整所需的最小指令数量。

int res=0;
for(int i=1;i<=n+1;i++)
{
    if(b[i]>0)
        res+=b[i];
}

在这个例子中,我们首先要增加温度以满足牛棚1和2的需求,然后降低温度以满足牛棚3的需求。简化计算,假设我们直接通过差分数组计算,结果如下:

  1. 升温2度以满足牛棚1的需求。
  2. 因为牛棚2也需要升温2度,所我们继续保持这个操作(实际上,这部分操作可能已经在差分数组计算中考虑过)。
  3. 最后,我们需要降温3度以满足牛棚3的需求。

简化的总结是,我们需要一系列升温和降温操作来达到目标状态。实际上,差分数组的计算和更新是为了找到这样一系列操作中的最小集合。

我希望这个例子能帮助理解较为抽象的差分更新和计算最小操作数的过程。实际上,代码中的逻辑更复杂,涉及预处理差分数组以便精确地计算出所需的最小操作数。

  • 27
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

命运从未公平

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值