本次博客我是通过Notion软件写的,转md文件可能不太美观,大家可以去我的博客中查看:北天的 BLOG,持续更新中,另外这是我创建的编程学习小组频道,想一起学习的朋友可以一起!!!
现在要对数组 V 进行 n 次操作。
第 i 次操作的具体流程如下:
注意:
请你输出所有操作完成后的数组 V。
输入格式
第一行包含整数 T,表示共有 T 组测试数据。
每组数据第一行包含整数 n。
第二行包含 n 个整数 a1,a2,…,an。
输出格式
每组数据输出一行结果,表示所有操作完成后的数组 V,数组内元素之间用空格隔开。
数据范围
1≤ T ≤20000,
1≤n≤2×10^5,
0≤a_i≤n,
保证一个测试点内所有 n 的和不超过 2×10^5。
输入样例:
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
上面的思路应该比较容易想到,但是这道题目的考点是差分思想,那么首先我们需要知道什么是差分思想。
什么是差分?
差分思想是一种常用的技巧,用于对序列中的区间操作进行优化。这种思想基于这样一个事实:对于序列中的任意一个区间,可以通过该区间的前缀和和后缀和之差来表示。
假设我们有一个长度为 n 的数组 a,其前缀和数组为 s,即 s[i] 表示 a 的前 i 个元素之和。那么 a 中某一区间 [l, r] 的和,就可以表示为 s[r] - s[l-1]。这个表示方法也被称为前缀和差分。类似地,我们可以定义后缀和数组 b 和后缀和差分,即 b[i] 表示 a 的后 i 个元素之和,a 中某一区间 [l, r] 的和,可以表示为 b[n-l+1] - b[n-r]。
通过使用差分思想,我们可以在 O(n) 的时间复杂度内完成对序列中的某个区间的操作,例如修改、求和等。具体来说,差分的思想是在操作的区间两端的前缀和或后缀和上修改对应的差分值,然后通过前缀和或后缀和的累加计算,获得修改后的序列。
差分思想广泛应用于算法竞赛中的一些经典问题,如区间加、区间减、区间修改等问题。
T = int(input())
while T:
T -= 1
n = int(input())
a = list(map(int, input().split()))
l = 2 * 10e5 + 10
for i in range(n, 0, -1):
l = min(l, i - a[i - 1] + 1)
if l <= i:
a[i - 1] = 1
print(' '.join(map(str, a)))
该段代码实现的思路是:首先获取用户输入的T和n,T表示测试用例的数量,n表示数组中元素的个数,然后从用户输入中获取数组a,然后从数组a末尾开始遍历,记录变量l用于记录最小的i-a[i-1]的值,如果l小于等于i,则将a[i-1]的值置为1,最后输出更新后的数组a。
使用差分思路实现如下:
for _ in range(int(input())):
n,a=int(input()),list(map(int,input().split()))
arr=[0]*(n+5)
for i in range(n):
s=max(0,i-a[i]+1)
arr[s]+=1
arr[i+1]-=1
for i in range(1,n):
arr[i]+=arr[i-1]
print(*[1 if b else 0 for b in arr[:n]],sep=' ')
在这段代码中,差分的思想被用于计算一个数组 arr
,该数组表示每个位置上的元素与其前一个位置上的元素的差值。为了实现这个思想,代码中首先创建一个长度为 n+5
的全零数组 arr
,其中 n
是输入中给定的数组的长度。接着,代码使用一个循环遍历数组中的所有元素。在每次循环中,代码计算当前元素所对应区间的起始位置 s
,并将 arr[s]
的值加上 1
,同时将 arr[i+1]
的值减去 1
,这样 arr
数组中的差分值就被更新了。最后,代码使用一个循环遍历数组中的所有位置,将 arr
数组中的差分值累加起来,从而得到数组中每个位置的实际值。
最后一步中,代码将 arr
数组中的前 n
个元素转换为 0
或 1
,其中 1
表示对应位置上的原始数组中有一个元素,而 0
则表示对应位置上的原始数组中没有元素。这样,代码就完成了对原始数组的处理,并输出了最终结果。