题目
给定一个空数组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×105,
0≤ai≤n,
保证一个测试点内所有 n的和不超过 2×105。
输入样例:
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
分析题目
由这题不难想到,设整数数组为arr,若arr[i]为m (0<m) ,则V[i]到V[i-m+1]都是1(若m>i+1,则是V[i]到V[0]为1。思路十分简单,但是如何批量让数组某一段为1,且时间复杂度最小呢?
这里就涉及到差分,详情请看知识点,然后我们上代码
#include<bits/stdc++.h>
using namespace std;
const int N=200010;
int main() {
int n;
cin >> n;
int x;
int v[N];
while(n--) {
int num;
cin >> num;
memset(v,0,(num+1)*4);
for (int j = 1; j<=num; j++) {
cin >> x;
if (x) {
int p = min(j+1,x);
v[j-p+1]++;v[j+1]--;
}
}
for (int j = 1; j <= num; j++) {
v[j]+=v[j-1];
}
for(int j=1;j<=num;j++){
printf("%d ",!!v[j]);
}
puts("");
}
return 0;
}
注意事项
V数组里只有0和1,如果使用差分会出现超过1的情况,所以需要使用!!V[i]
知识点:
差分:
如果一个数组arr1的大小为n,想要对其下标a~b进行批量加k的操作。可以先得到它的差分数组arr2
arr2[i]=arr1[i]-arr1[i-1]
再对a~b进行批量操作
arr2[a]+=k,arr2[b+1]-=k
最后再利用前缀和求出新的arr1
arr1[i]=arr1[i-1]+arr2[i]
memset:
按照字节对内存块进行初始化,不能用它将int数组出初始化为0和-1之外的其他值
void *memset(void *s, int c, size_t n);
memset(v,0,(num+1)*4)
s代表填充的内存块,c为填充值,n表示填充的个数(本题实例中(num+1)*4代表填充num+1,乘4则是因为int的4个字节)