【蓝桥杯每日一题】3.4 空调

【蓝桥杯每日一题】3.4 空调

原题链接:4262. 空调 - AcWing题库

差分思想:

参考:林小鹿差分详解

首先给定一个原数组 a a a : a [ 1 ] , a [ 2 ] , a [ 3 ] . . . a [ n ] a[1],a[2],a[3]...a[n] a[1],a[2],a[3]...a[n];

然后我们构造一个数组 b b b: b [ 1 ] , b [ 2 ] , b [ 3 ] . . . b [ i ] b[1],b[2],b[3]...b[i] b[1],b[2],b[3]...b[i]

使得:a[i]=b[1]+b[2]+…+b[i]

也就是说,a数组是b数组的前缀和数组,反过来我们把b数组叫做a数组的差分数组。换句话说,每一个a[i]都是b数组中从头开始的一段区间和。

如何构造差分数组b? 以下是最为直接的方法:

a [ 0 ] = 0 a[0 ]= 0 a[0]=0;

b [ 1 ] = a [ 1 ] − a [ 0 ] b[1] = a[1] - a[0] b[1]=a[1]a[0];

b [ 2 ] = a [ 2 ] − a [ 1 ] b[2] = a[2] - a[1] b[2]=a[2]a[1];

b [ 3 ] = a [ 3 ] − a [ 2 ] b[3] =a [3] - a[2] b[3]=a[3]a[2];

b [ n ] = a [ n ] − a [ n − 1 ] b[n] = a[n] - a[n-1] b[n]=a[n]a[n1];

反过来,我们只要有b数组,通过前缀和运算,就可以在 O ( n ) O(n) O(n) 的时间内得到a数组 。

有这么一个问题:

给定区间 [ l , r ] [l ,r ] [l,r],让我们把a数组中的 [ l , r ] [ l, r] [l,r]区间中的每一个数都加上 c c c,即 a [ l ] + c , a [ l + 1 ] + c , a [ l + 2 ] + c . . . . a [ r ] + c a[l] + c , a[l+1] + c , a[l+2] + c....a[r] + c a[l]+c,a[l+1]+c,a[l+2]+c....a[r]+c;

暴力做法是for循环 l l l r r r区间,时间复杂度 O ( n ) O(n) O(n),如果我们需要对原数组执行m次这样的操作,时间复杂度就会变成 O ( n ∗ m ) O(n*m) O(nm)。有没有更高效的做法吗? 考虑差分做法。

始终要记得,a数组是b数组的前缀和数组,比如对 b b b数组的 b [ i ] b[i] b[i]的修改,会影响到a数组中从a[i]及往后的每一个数。

首先让差分b数组中的 b [ l ] + c b[l] + c b[l]+c , a a a数组变成 a [ l ] + c a[l] + c a[l]+c , a [ l + 1 ] + c . . . a [ n ] + c a[l+1] + c... a[n] + c a[l+1]+c...a[n]+c;

然后我们打个补丁, b [ r + 1 ] − c b[r+1] - c b[r+1]c, a a a数组变成 a [ r + 1 ] − c , a [ r + 2 ] − c . . . a [ n ] − c a[r+1] - c,a[r+2] - c...a[n] - c a[r+1]c,a[r+2]c...a[n]c;

画图理解:

差分数组理解

b [ l ] + c b[l] + c b[l]+c,效果使得a数组中 a [ l ] a[l] a[l]及以后的数都加上了 c c c (红色部分),但我们只要求l到r区间加上 c c c, 因此还需要执行 b [ r + 1 ] − c b[r+1] - c b[r+1]c,让 a a a数组中 a [ r + 1 ] a[r+1] a[r+1]及往后的区间再减去 c c c(绿色部分),这样对于a[r] 以后区间的数相当于没有发生改变。

因此我们得出一维差分结论:给 a a a数组中的 [ l , r ] [ l, r] [l,r]区间中的每一个数都加上 c c c,只需对差分数组b做 b [ l ] + = c b[l] + = c b[l]+=c, b [ r + 1 ] − = c b[r+1] - = c b[r+1]=c。时间复杂度为 O ( 1 ) O(1) O(1), 大大提高了效率。

思考:

目标数组为:1 5 3 3 4

初始数组为:1 2 2 2 1

目标-现在:0 3 1 1 3 也即是初始数组需要进行以上变化

所以可以看做:0 0 0 0 0–>0 3 1 1 3或者是0 3 1 1 3–>0 0 0 0 0

通过每次变化一段连续区间进行+1或者-1,故使用差分数组。差分数组中b[i]+c,b[j+1]-c 就可以实现把a[]数组中[i,j]加上c

03113的差分数组为 0 3 -2 0 2,
对于差分数组,现在有两种操作:
①选两个数,一个+1一个-1
②选一个数,+1或-1

通过这两种操作将差分数组变成0 0 0 0 0,最少次数就是全用操作①,但是如果正数的和不等于负数的和,则肯定需要使用操作②,所以最少操作次数 = max(正数和,|负数和|)

AC代码:
#include<iostream>
#include<algorithm>
#include<cmath>
using namespace std;

int N;
int p[100010],t[100010];
int cha[100010];
int main()
{
    cin>>N;
    for(int i=1;i<=N;i++) cin>>p[i];
    for(int i=1;i<=N;i++)
    {
        cin>>t[i];
        t[i]=p[i]-t[i];
    }
    int sum1=0,sum2=0;
    //求查分数组,同时分别统计正负数的和
    for(int i=1;i<=N;i++)
    {
        cha[i]=t[i]-t[i-1];
        cha[i]>0? sum1+=cha[i]:sum2+=cha[i];
    }
    cout<<max(sum1,abs(sum2));
    return 0;
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值