ACwing算法备战蓝桥杯——Day2——差分

理论知识:

总的来说:差分简单来讲就是前缀和的逆过程

定义:

假设有一个递增序列s[N],有一个序列a[N]满足{ a1=s1 , a2=s2-s1 , a3=s3-s2 ..... an=sn-sn- 1 }

那么a序列就称为s序列的差分序列;

最常用性质:

有一个数组a[n],其对应的差分数组b[n]为b1=a1,b2=a2-a1,b3=a3-a2......bn=an-an-1;
如果要对原数组的[l,r]区间上的数同时增加一个大小为c的数,暴力给每个数加上c,时间复杂度为O(n),在其对应的差分数组上
进行inerst操作则可以实现插入时间复杂度为O(1).(主要作用就是降低时间复杂度,可以看作是对暴力算法的优化,即剪枝)
类似于连锁效应,底层的数组b发生改变,作为b数组前缀和的a数组会发生一连串的变化,使得时间复杂度缩小。
 void inerst(int l,int r,int c) 
{
     b[l]+=c;
    b[r+1]-=c;
}

(对于如何在已知s[]序列时,利用inerst()函数巧妙得求出对应的差分数组,可移步至查看→链接;

实践例题:

今日份刷题:k倍区间和,改变数组元素,差分,差分矩阵,增减数列;

如果对“k倍区间“感兴趣的见→链接

下面分享例题”改变数组元素

题目

给定一个空数组 V 和一个整数数组 a1,a2,…,an。

现在要对数组 V 进行 n 次操作。

第 i 次操作的具体流程如下:

从数组 V 尾部插入整数 0。
将位于数组 V 末尾的 ai 个元素都变为 1(已经是 1 的不予理会)。
注意:

ai 可能为 0,即不做任何改变。
ai 可能大于目前数组 V 所包含的元素个数,此时视为将数组内所有元素变为 1。
请你输出所有操作完成后的数组 V。

输入格式
第一行包含整数 T,表示共有 T 组测试数据。

每组数据第一行包含整数 n。

第二行包含 n 个整数 a1,a2,…,an。

输出格式
每组数据输出一行结果,表示所有操作完成后的数组 V,数组内元素之间用空格隔开。

数据范围
1≤T≤20000,
1≤n≤2×1e5,
0≤ai≤n,
保证一个测试点内所有 n 的和不超过 2×1e5。

输入样例:
3
6
0 3 0 0 1 3
10
0 0 0 1 0 5 0 0 0 2
3
0 0 0
输出样例:
1 1 0 1 1 1
0 1 1 1 1 1 0 0 1 1
0 0 0

代码+题解:

有助于理解的关键代码都会加上注释

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int N=2e5+10;//观察题目会发现一开始的数据就必须会有两层循环,时间复杂度达到了4e9;
int q[N],v[N];
void Inerst(int l,int r){//inerst函数对差分数组处理
    v[l]+=1;
    v[r+1]-=1;
    return;
}
int main(){
    int T;
    cin>>T;
    while(T--){
        int n;
        cin>>n;
        memset(q,0,n*4);//这里尽量缩小数据范围,不要使用N,时间会有几倍差.这里简单讲一下memset的用法:第                           一个参数是目标起始地址,第二个参数是需要设定的值,第三个是总的字节大小;memset                           是按字节处理的,所以第三个参数可以使用sizeof()作为参数;其头文件为#include <c                           string>
        memset(v,0,n*4);
        for(int i=1;i<=n;i++)
            scanf("%d",&q[i]);//储存每组数据
        for(int i=1;i<=n;i++){
            if(!q[i]) continue;//特判,是q[i]==0就跳过
            if(i<=q[i]) Inerst(1,i);//这里最为关键,不需要考虑考虑区间是否重复加1
            else Inerst(i-q[i]+1,i);
        }
        for(int i=1;i<=n;i++) v[i]+=v[i-1];//已知差分数组,求原数组,直接求前缀和
        for(int i=1;i<=n;i++){//代码30~31可以使用cout<<!!v[i]<<' ';来代替(双非)
            if(v[i]) cout<<1<<' ';
            else cout<<0<<' ';
        };
        cout<<endl;
    }
    return 0;
}

总结:

1.值得高兴的是在解”改变数组元素“时学会了使用数据debug,成功AC;

2.解题还是得多注意数据范围;

如有哪里有疑惑的地方还请评论区留言,如果有错误的地方希望多多指教~~~///(^v^)\\\~~~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

切勿踌躇不前

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

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

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

打赏作者

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

抵扣说明:

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

余额充值