算法题——改变数组元素

题目:改变数组元素

给一个空数组v和一个整数数组a,对数组v进行n次操作,第i次操作为在数组v尾部插入整数0,将位于数组v尾部的a[i]个元素都变为1。这里需要注意a[i]可能为0,该情况不做任何改变,a[i]也可能大于当前数组v的元素个数,此时把数组v内所有元素都变为1。

输入有T组测试数据,每组数据第一行输入整数n,第二行输入n个整数,这里T最大20000,n最大200000,并且每一个测试点内的n的和不超过200000,那么一次遍历最多20000x200000,因此时间复杂度要控制在O(nlogn)以内。

本题实际上是把某一个区间内的元素变成1,因此可以用差分法解决,差分法主要解决的问题是某个区间所有元素都加上一个数,本题也可以转化为每个元素都加上一个数的形式。

差分

一维差分

差分就是前缀和的逆运算,对于前缀和数组a,a[i]是自己以及前面所有元素的和,也即a[i]=a[i]+a[i-1],再设一个数组b,a[i]=b[1]+b[2]+...+b[i],对于这样的两个数组,数组a是数组b的前缀和,数组b是数组a的差分。

差分的用处在于,当我们把一个区间[l,r]同时加上或减去同一个数tmp,可以直接遍历,时间复杂度为O(n),如果要进行m次相加或相减,时间复杂度为O(n*m),这样时间复杂度过高。此时可以用差分数组,[l,r]区间加上(或减去)tmp等价于差分数组[l]+tmp,[r+1]-tmp,这样计算前缀和时,[l+1]=[l+1]+[l],也即[l+1]也加上了tmp,到[r+1]时,该元素先减去一个tmp,后加上一个tmp,前后相抵消,此时只有[l,r]区间都加上了tmp,并且时间复杂度为O(n)。

代码

#include<iostream>
#include<stdio.h>
#include<algorithm>
#include<cstring>
using namespace std;
const int N = 200000+10;
int T,n,a[N];
int main()
{
    cin>>T;
    while(T--)
    {
        int tmp;
        cin>>n;
        //memset(a, 0 ,sizeof(a));
        memset(a, 0, (n+1)*4);
        for(int i=1; i<=n; ++i)
        {
            cin>>tmp;
            tmp=min(tmp, i);
            int l=i-tmp+1, r=i;
            a[l]++, a[r+1]--;
        }
        for(int i=1; i<=n; ++i) a[i]+=a[i-1];
        for(int i=1; i<=n; ++i)
        {
            if(a[i]) cout<<"1 ";
            else cout<<"0 ";
            //cout<<!!a[i];
            //如果a[i]不为0,!a[i]为0,!!a[i]就为1,也即a[i]被操作过就是1,同理当a[i]为0时,结果为0
        }
        cout<<endl;
    }
    return 0;
}

这里memset的写法只初始化可能用到的地方(一个int是4个字节,所以乘4),节省时间。

posted @ 2023-02-17 23:49  HD0117  阅读(24)  评论(0编辑  收藏  举报